You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为不同数据集的两个散点子图设置一致的颜色映射?

解决MNIST UMAP散点子图的颜色映射与图例一致性问题

核心问题分析

  • 当前代码直接基于总类别数生成调色板,但Seaborn会按子图内存在的类别顺序分配颜色,导致两个子图中同一类别对应不同颜色
  • 当某个类别在子图数据中缺失时,该类别会从对应图例中消失,造成跨图图例不统一

解决方案:创建类别到颜色的固定映射字典

要实现统一的颜色映射,关键是为整个数据集的所有类别预先绑定固定颜色,而非依赖Seaborn自动分配。具体步骤:

  1. 提取并排序所有唯一类别,保证顺序固定
  2. 基于类别数量生成调色板,将类别与颜色一一对应成字典
  3. 绘制子图时使用该字典作为调色板,同时通过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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 15:10:36