如何为不同数据集的两个散点子图设置一致的颜色映射?
解决MNIST UMAP散点子图的颜色映射与图例一致性问题
核心问题分析
- 当前代码直接基于总类别数生成调色板,但Seaborn会按子图内存在的类别顺序分配颜色,导致两个子图中同一类别对应不同颜色
- 当某个类别在子图数据中缺失时,该类别会从对应图例中消失,造成跨图图例不统一
解决方案:创建类别到颜色的固定映射字典
要实现统一的颜色映射,关键是为整个数据集的所有类别预先绑定固定颜色,而非依赖Seaborn自动分配。具体步骤:
- 提取并排序所有唯一类别,保证顺序固定
- 基于类别数量生成调色板,将类别与颜色一一对应成字典
- 绘制子图时使用该字典作为调色板,同时通过
hue_order指定所有类别,确保图例完整显示
修改后的完整代码
import os.path from torch import load import numpy as np import matplotlib.pyplot as plt import matplotlib.colors as mcolors import seaborn as sns import pandas as pd def plotSideBySide(combinedData: pd.DataFrame, superTitle: str, path: str = None, showVisuals = False): dataSources = combinedData["dataSource"].unique() if len(dataSources)>2: print("ERROR: dataset contains more than 2 dataSources ") dataSources = dataSources[:2] f1 = combinedData.loc[(combinedData['dataSource']==dataSources[0])] f2 = combinedData.loc[(combinedData['dataSource']==dataSources[1])] # 获取所有唯一类别并排序,确保类别顺序固定 all_classes = sorted(combinedData["y"].unique()) n_colors = len(all_classes) # 创建类别到颜色的固定映射字典 palette = dict(zip(all_classes, sns.color_palette("Paired", n_colors=n_colors))) x1_range = (combinedData.min()["x1"], combinedData.max()["x1"]) x2_range = (combinedData.min()["x2"], combinedData.max()["x2"]) fig = plt.figure() ax1 = fig.add_subplot(121) ax2 = fig.add_subplot(122) # 使用固定调色板字典,同时指定hue_order确保图例包含所有类别 sns.scatterplot(data=f1, x='x1', y='x2', hue='y', palette=palette, hue_order=all_classes, alpha=.5, ax=ax1) sns.scatterplot(data=f2, x='x1', y='x2', hue='y', palette=palette, hue_order=all_classes, alpha=.5, ax=ax2) leftTitle = f"plot for the {dataSources[0]} data" rightTitle = f"plot for the {dataSources[1]} data" for index,axis in enumerate(fig.axes): axis.set( title=[leftTitle,rightTitle][index], xlim=x1_range, ylim=x2_range, xlabel=None, ylabel=None ) # 调整图例位置,避免遮挡图形 axis.legend(title='Digit', bbox_to_anchor=(1.05, 1), loc='upper left') plt.suptitle(superTitle) plt.tight_layout() # 自动调整布局,防止图例被截断 if path!=None: plt.savefig(path, bbox_inches='tight') # 保存时包含完整图例 if showVisuals: plt.show()
关键修改点说明
- 固定类别顺序:通过
sorted()对所有类别排序,避免因类别出现顺序变化导致颜色映射混乱 - 调色板字典:用
dict(zip())将每个类别与固定颜色绑定,确保两个子图中同一类别颜色完全一致 - hue_order参数:指定所有类别作为hue_order,即使子图中没有某个类别,图例仍会保留该类别位置(颜色为空,不影响一致性)
- 布局优化:添加
plt.tight_layout()和bbox_inches='tight',解决图例被截断的问题
针对你之前思路的说明
你考虑的“为两个子图分别创建调色板并移除不存在类别”不可行——这样会导致两个调色板的颜色索引对应不同类别,反而加剧颜色不一致。而不指定调色板时,Seaborn会按子图内类别顺序自动分配颜色,同样会造成跨图映射混乱,所以固定映射字典是最优方案。
内容的提问来源于stack exchange,提问作者Konstantin Frunzek
相关产品推荐
相关产品推荐

