如何为单个Matplotlib散点图添加两个不同条件归一化的色条?
正确实现方案
你不需要绘制零大小的假散点来生成色条,matplotlib的colorbar支持直接绑定ScalarMappable对象生成独立色条,不会影响已有散点的颜色映射,完整可运行代码如下:
import numpy as np import matplotlib.pyplot as plt import matplotlib as mpl from mpl_toolkits.axes_grid1 import make_axes_locatable # 读取数据 a,b,c,d,e = np.loadtxt('test.txt', delimiter='\t', unpack=True, skiprows=1, dtype=str) a = a.astype(np.float64) c = c.astype(np.float64) d = d.astype(np.float64) e = e.astype(np.float64) b = list(b) fig, ax = plt.subplots(figsize=(10,6)) # 散点颜色绑定e列的映射规则 norm_e = mpl.colors.Normalize(vmin=e.min(), vmax=e.max()) cmap = 'Reds' # 绘制真实散点,用掩码批量处理代替循环效率更高 alpha_mask = np.array(b) == 'alpha' beta_mask = np.array(b) == 'beta' ax.scatter(a[alpha_mask], e[alpha_mask], marker='o', edgecolors='black', alpha=0.8, s=120, c=e[alpha_mask], norm=norm_e, cmap=cmap) ax.scatter(a[beta_mask], e[beta_mask], marker='d', edgecolors='black', alpha=0.8, s=120, c=e[beta_mask], norm=norm_e, cmap=cmap) # 为c列创建对应的ScalarMappable,用于生成第一个色条 norm_c = mpl.colors.Normalize(vmin=c.min(), vmax=c.max()) sm_c = mpl.cm.ScalarMappable(norm=norm_c, cmap=cmap) sm_c.set_array([]) # 为d列创建对应的ScalarMappable,用于生成第二个色条 norm_d = mpl.colors.Normalize(vmin=d.min(), vmax=d.max()) sm_d = mpl.cm.ScalarMappable(norm=norm_d, cmap=cmap) sm_d.set_array([]) # 坐标轴配置 years_ax = np.linspace(2000, 2021, 21, endpoint=True, dtype=int) ax.set_xticks(years_ax) plt.xticks(rotation=45) plt.grid(True, which="both", ls="-", alpha=0.1) plt.xlabel('Years', fontsize=14) plt.ylabel('e', fontsize=14) ax.tick_params(axis='both', which='major', labelsize=14) # 创建色条容器 divider = make_axes_locatable(ax) cax1 = divider.new_vertical(size='5%', pad=0.5) cax2 = divider.new_vertical(size='5%', pad=0.7) fig.add_axes(cax1) fig.add_axes(cax2) # 生成第一个色条(对应c列取值范围) cb1 = plt.colorbar(sm_c, cax=cax1, orientation='horizontal') cb1.ax.xaxis.set_ticks_position('top') cb1.set_label('c值范围', fontsize=12) # 生成第二个色条(对应d列取值范围,反转坐标轴) cb2 = plt.colorbar(sm_d, cax=cax2, orientation='horizontal') cb2.ax.invert_xaxis() cb2.ax.xaxis.set_ticks_position('top') cb2.set_label('d值范围', fontsize=12) # 调整布局避免标签被遮挡 plt.tight_layout() plt.show()
关键修改说明
- 去掉了所有零大小假散点的绘制逻辑,避免干扰散点本身的颜色映射
- 散点绘制改用掩码批量处理,代替逐点循环,运行效率更高
- 直接使用
ScalarMappable绑定不同列的归一化规则生成色条,完全匹配散点的配色方案 - 水平色条反转直接调用
invert_xaxis()实现,符合可读性要求
内容的提问来源于stack exchange,提问作者eln05
相关产品推荐
相关产品推荐

