两个子图上的两个颜色条,同一图

时间:2018-06-19 23:20:03

标签: python matplotlib plot data-visualization colorbar

我正在尝试制作一个带有两个子图的matplotlib图,每个子图的右侧都有一个色条。这是我的当前代码:

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from mpl_toolkits.axes_grid1 import make_axes_locatable

X = tsne_out[:,0]
Y = tsne_out[:,1]
Z = tsne_out[:,2]

fig = plt.figure(figsize = (20,15))
ax1 = fig.add_subplot(221)
ax1.scatter(X, Y, c = material, s = df['Diameter (nm)']/4, cmap = plt.get_cmap('nipy_spectral', 11))
ax1.set_title("2D Representation", fontsize = 18)
ax1.set_xlabel("TSNE1", fontsize = 14)
ax1.set_ylabel("TSNE2", fontsize = 14)
ax1.set_xlim(-20,20)
ax1.set_ylim(-20,20)
ax1.set_xticks(list(range(-20,21,10)))
ax1.set_yticks(list(range(-20,21,10)))


cbar = fig.colorbar(cax, ticks=list(range(0,9)))
cbar.ax.tick_params(labelsize=15) 
cbar.ax.set_yticklabels(custom_ticks)  # horizontal colorbar


ax2 = fig.add_subplot(222, projection='3d')
ax2.scatter(X, Y, Z, c = material, s = df['Diameter (nm)']/4, cmap = plt.get_cmap('nipy_spectral', 11))
ax2.set_title("3D Representation", fontsize = 18)
ax2.set_xlabel("TSNE1", fontsize = 14)
ax2.set_ylabel("TSNE2", fontsize = 14)
ax2.set_zlabel("TSNE3", fontsize = 14)
ax2.set_xlim(-20,20)
ax2.set_ylim(-20,20)
ax2.set_zlim(-20,20)
ax2.set_xticks(list(range(-20,21,10)))
ax2.set_yticks(list(range(-20,21,10)))
ax2.set_zticks(list(range(-20,21,10)))

cbar = fig.colorbar(cax, ticks = list(range(0,9)))
cbar.ax.tick_params(labelsize=15) 
cbar.ax.set_yticklabels(custom_ticks)

这提供了下图: Matplotlib produced figure

我的问题是:为什么第一个颜色栏不显示我的自定义刻度,我该如何解决?

1 个答案:

答案 0 :(得分:2)

问题似乎是ScalarMappable个对象似乎最多可以与它们关联一个颜色条。当您使用相同的ScalarMappable绘制第二个颜色条时,原始颜色条将取消链接,并且第一个颜色条的先前设置将丢失。

您的代码缺少一些细节(特别是cax的定义),因此您要么必须创建两个单独的mappable,要么直接使用每个scatter调用给您的内容。此外,我会明确指出您要在何处插入颜色条。

一个示例修复程序,假设cax确实是指您的散点图:

import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np

X = np.random.rand(100) * 40 - 20
Y = np.random.rand(100) * 40 - 20
Z = np.random.rand(100) * 40 - 20
C = np.random.randint(1,8,100)
custom_ticks = list('ABCDEFGH')

fig = plt.figure(figsize = (20,15))
ax1 = fig.add_subplot(121)
sc1 = ax1.scatter(X, Y, c = C, cmap='viridis') # use this mappable
ax1.set_title("2D Representation", fontsize = 18)
ax1.set_xlabel("TSNE1", fontsize = 14)
ax1.set_ylabel("TSNE2", fontsize = 14)
ax1.set_xlim(-20,20)
ax1.set_ylim(-20,20)
ax1.set_xticks(list(range(-20,21,10)))
ax1.set_yticks(list(range(-20,21,10)))


cbar = fig.colorbar(sc1, ax=ax1, ticks=list(range(0,9))) # be explicit about ax1
cbar.ax.tick_params(labelsize=15) 
cbar.ax.set_yticklabels(custom_ticks)

ax2 = fig.add_subplot(122, projection='3d')
sc2 = ax2.scatter(X, Y, Z, c=C, cmap='viridis') # next time use this one
ax2.set_title("3D Representation", fontsize = 18)
ax2.set_xlabel("TSNE1", fontsize = 14)
ax2.set_ylabel("TSNE2", fontsize = 14)
ax2.set_zlabel("TSNE3", fontsize = 14)
ax2.set_xlim(-20,20)
ax2.set_ylim(-20,20)
ax2.set_zlim(-20,20)
ax2.set_xticks(list(range(-20,21,10)))
ax2.set_yticks(list(range(-20,21,10)))
ax2.set_zticks(list(range(-20,21,10)))

cbar = fig.colorbar(sc2, ax=ax2, ticks=list(range(0,9))) # sc1 here is the bug
cbar.ax.tick_params(labelsize=15) 
cbar.ax.set_yticklabels(custom_ticks)

plt.show()

这将产生以下结果:

created figure, fixed colorbar

请注意,我为您创建了一个MCVE,并且简化了一些事情,例如子图的数量。关键是,颜色条设置现在使用了独立的可映射对象,因此仍然保持不变。


另一个选择是先创建颜色条(如果需要,可以使用相同的ScalarMappable),然后再自定义两者:

sc = ax1.scatter(X, Y, c = C, cmap='viridis')
cbar1 = fig.colorbar(sc, ax=ax1, ticks=np.arange(0,9))
ax2.scatter(X, Y, Z, c=C, cmap='viridis')
cbar2 = fig.colorbar(sc, ax=ax2, ticks=np.arange(0,9)) # sc here too

for cbar in cbar1,cbar2:
    cbar.ax.tick_params(labelsize=15) 
    cbar.ax.set_yticklabels(custom_ticks)

以上所述的事实可能表明原始行为是一个错误。