I'm trying to plot 8 colorbars of a colormesh plot in matplotlib using the same colormap with 8 colors. Each one of the colorbars containing 1 color of the colormap. The original code I was using:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
from mpl_toolkits.axes_grid1 import make_axes_locatable
from matplotlib.ticker import FormatStrFormatter
plt.rcParams.update({
'font.size': 8
})
def make_plot(ax, data, colormap, ticks, custom_cbar):
ax.set_aspect('equal')
divider = make_axes_locatable(ax)
if custom_cbar == True:
plot = ax.pcolormesh(data, cmap = colormap, vmin=np.min(data) - 0.5, vmax=np.max(data) 0.5)
cax = divider.append_axes("top", size = '15%', pad = 0.05)
cbar = plt.colorbar(plot, ax=ax, cax = cax, orientation='horizontal', ticks = ticks)
cbar.ax.set_xticklabels(['A', 'B', 'C', 'D', 'E', 'F', 'Gh', 'KGh' ])
cbar.ax.tick_params(size=0, labelsize=6)
cbar.outline.set_visible(False)
else:
plot = ax.pcolormesh(data, cmap = colormap)
cax = divider.append_axes("top", size = '15%', pad = 0.05)
cbar = plt.colorbar(plot, ax=ax, cax = cax, orientation='horizontal', format = '%.3f', ticks = ticks)
cbar.ax.tick_params(direction = 'in', labelsize = 6)
cbar.ax.xaxis.set_ticks_position('top')
ax.yaxis.set_major_formatter(FormatStrFormatter('%g'))
ax.xaxis.set_major_formatter(FormatStrFormatter('%g'))
# ===================== Data =================== #
np.random.seed(17172721)
data_int = np.random.randint(8, size=(10,30))
ticks_int = [0,1,2,3,4,5,6,7]
data = np.random.random((10,30))
delta_data = data.max() - data.min()
ticks = [data.min(), 0.5*delta_data, data.max()]
# ===================== Figure =================== #
cm = 1/2.54
fig = plt.figure(1, figsize = (15*cm, 8*cm), dpi = 227, constrained_layout = True)
ax1 = fig.add_subplot(2,2,1)
ax2 = fig.add_subplot(2,2,2)
ax3 = fig.add_subplot(2,2,3)
ax4 = fig.add_subplot(2,2,4)
# ===================== Plot =================== #
colormap = ListedColormap(['#404040', '#FFEE00', '#00DC00', '#FF8000', '#9900FF', '#007BFF', '#FF0000','#700000'])
make_plot(ax1, data_int, colormap, ticks_int, True)
make_plot(ax2, data, 'rainbow', ticks, False)
make_plot(ax3, data, 'rainbow', ticks, False)
make_plot(ax4, data, 'rainbow', ticks, False)
plt.show()
The original code produces this Figure:
Does anyone know how to do this and keep the alignment with all other subplots?
EDIT:
Based on JohanC comments, this implemented version of the code produces a good solution for some cases:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
from mpl_toolkits.axes_grid1 import make_axes_locatable
from matplotlib.ticker import FormatStrFormatter
plt.rcParams.update({
'font.size': 8
})
def make_plot(ax, data, colormap, ticks, custom_cbar):
ax.set_aspect('equal')
divider = make_axes_locatable(ax)
if custom_cbar == True:
plot = ax.pcolormesh(data, cmap = colormap, vmin=np.min(data) - 0.5, vmax=np.max(data) 0.5)
cax = divider.append_axes("top", size = '15%', pad = 0.05)
cbar = plt.colorbar(plot, ax=ax, cax = cax, orientation='horizontal', ticks = ticks, drawedges=True)
cbar.ax.set_xticklabels(['A', 'B', 'C', 'D', 'E', 'F', 'Gh', 'KGh' ])
cbar.ax.tick_params(size=0, labelsize=6)
cbar.outline.set_edgecolor('white')
cbar.outline.set_linewidth(2.5)
cbar.dividers.set_color('white')
cbar.dividers.set_linewidth(2.5)
else:
plot = ax.pcolormesh(data, cmap = colormap)
cax = divider.append_axes("top", size = '15%', pad = 0.05)
cbar = plt.colorbar(plot, ax=ax, cax = cax, orientation='horizontal', format = '%.3f', ticks = ticks)
cbar.ax.tick_params(direction = 'in', labelsize = 6)
cbar.ax.xaxis.set_ticks_position('top')
ax.yaxis.set_major_formatter(FormatStrFormatter('%g'))
ax.xaxis.set_major_formatter(FormatStrFormatter('%g'))
# ===================== Data =================== #
np.random.seed(17172721)
data_int = np.random.randint(8, size=(10,30))
ticks_int = [0,1,2,3,4,5,6,7]
data = np.random.random((10,30))
delta_data = data.max() - data.min()
ticks = [data.min(), 0.5*delta_data, data.max()]
# ===================== Figure =================== #
cm = 1/2.54
fig = plt.figure(1, figsize = (15*cm, 8*cm), dpi = 227, constrained_layout = True)
ax1 = fig.add_subplot(2,2,1)
ax2 = fig.add_subplot(2,2,2)
ax3 = fig.add_subplot(2,2,3)
ax4 = fig.add_subplot(2,2,4)
# ===================== Plot =================== #
colormap = ListedColormap(['#404040', '#FFEE00', '#00DC00', '#FF8000', '#9900FF', '#007BFF', '#FF0000','#700000'])
make_plot(ax1, data_int, colormap, ticks_int, True)
make_plot(ax2, data, 'rainbow', ticks, False)
make_plot(ax3, data, 'rainbow', ticks, False)
make_plot(ax4, data, 'rainbow', ticks, False)
plt.show()
This modified version of the code produces this output:
However, in this case, it is still plotting 1 colorbar with the full colormap. The idea is to plot 8 colorbars next to each other and each one with 1 color of the colormap.
Thanks in advance!
CodePudding user response:
One could draw white vertical lines onto the colorbar:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
fig, ax = plt.subplots(figsize=(12, 5))
ax.set_aspect('equal')
divider = make_axes_locatable(ax)
ticklabels = ['A', 'B', 'C', 'D', 'E', 'F', 'Gh', 'KGh']
nticks = len(ticklabels)
colormap = plt.get_cmap('turbo', nticks)
data = np.random.randint(0, nticks, (8, 12))
cmesh = ax.pcolormesh(data, cmap=colormap, vmin=np.min(data) - 0.5, vmax=np.max(data) 0.5)
cax = divider.append_axes("top", size='15%', pad=0.2)
cbar = plt.colorbar(cmesh, ax=ax, cax=cax, orientation='horizontal', ticks=np.arange(nticks))
cbar.ax.set_xticklabels(['A', 'B', 'C', 'D', 'E', 'F', 'Gh', 'KGh'])
cbar.ax.tick_params(size=0, labelsize=6)
cbar.outline.set_visible(False)
for x in np.arange(nticks 1) - 0.5:
cbar.ax.axvline(x, color='white', lw=5)
plt.tight_layout()
plt.show()
CodePudding user response:
Based on the @JohanC suggestion, I've come with a temporary solution by adding the option drawedges = True
when calling the method to plot as:
cbar = plt.colorbar(plot, ax=ax, cax = cax, orientation='horizontal', ticks = ticks, drawedges=True)
This option draw dividers between colorbar levels. Then I used the following methods:
cbar.outline.set_edgecolor('white')
cbar.outline.set_linewidth(2.5)
cbar.dividers.set_color('white')
cbar.dividers.set_linewidth(2.5)
which makes the colorbar outline and dividers white, and define its width.
The result can be seen in this Image:
Although it is not the solution I'm seeking, it is a good solution to some cases. Unfortunately my concern is yet on how to divide the colorbar utilizing the same colormap. I'll edit the question posting this solution.