如何提取Seaborn散点图图例形状并分配给颜色分组?
需求说明
- 目标:制作结合颜色与形状的Seaborn散点图,切换变量映射逻辑:不再将颜色分配给形状,而是将形状条目分配给颜色条目
- 当前问题:已实现「颜色分配给形状」的功能,但图表视觉混乱(蓝色占比过大)
- 期望调整:设置
hue='Shorthand'、style='Subscale',实现形状与颜色图例条目的关联
现有实现代码
#subscale_dict = {'Deccan Traps': 'CFB', 'Other fissure': 'Fissure', 'Experimental': 'Experimental', 'Stratovolcano': 'Stratovolcano', # 'Columbia river basalts': 'CFB', 'Iceland': 'Fissure', 'Shield': 'Shield', 'Ferrar': 'CFB', 'Emeishan': 'CFB', # 'EquiMAP': 'CFB', 'Moon': 'Moon'} subscale_dict = passframe.set_index("Shorthand")["Style"].to_dict() passframe['Subscale'] = passframe['Shorthand'].map(subscale_dict) passframe['Subscale'] = pd.Categorical(passframe['Subscale']) print(subscale_dict) passframe cust = {'axes.labelsize': 24, 'xtick.labelsize':20, 'ytick.labelsize':20, 'legend.fontsize':20, 'figure.facecolor': 'white'} sns.set(rc={'figure.figsize':(32,18)}) sns.set_theme(style = 'ticks', font = 'Calibri', rc = cust) sns.set_context('poster') colour = 'colorblind' fig1 = sns.scatterplot(data = passframe, x = 'Slope1', y = 'Intercept1', style = 'Shorthand', hue = 'Subscale',s = 400, palette = colour, legend = 'full')#, height = 12, aspect = 16/9) handles, labels = fig1.get_legend_handles_labels() index_item_title = labels.index('Shorthand') color_dict = {label: handle.get_facecolor() for handle, label in zip(handles[1:index_item_title], labels[1:index_item_title])} print(color_dict) # loop through the items, assign color via the subscale of the item idem for handle, label in zip(handles[index_item_title + 1:], labels[index_item_title + 1:]): handle.set_color(color_dict[subscale_dict[label]]) fig1.legend(handles[index_item_title + 1:], labels[index_item_title + 1:], title='Data', loc = 'best', markerscale = 2, labelspacing = 1.2, fontsize = 24, title_fontsize = 32) fig1.set_xlabel('$Slope (cm^{-1})$') fig1.set_ylabel('$Intercept (cm^{-4})$') plt.xlim([min(passframe['Slope1']), 1500]) plt.ylim([min(passframe['Intercept1']-2), max(passframe['Intercept2'])+2])
当前实现效果

修改后的代码实现
核心调整:交换hue与style的映射变量,重构图例逻辑实现形状到颜色条目的分配
import seaborn as sns import pandas as pd import matplotlib.pyplot as plt # 构建Subscale映射字典 subscale_dict = passframe.set_index("Shorthand")["Style"].to_dict() passframe['Subscale'] = passframe['Shorthand'].map(subscale_dict) passframe['Subscale'] = pd.Categorical(passframe['Subscale']) # 绘图样式配置 cust = {'axes.labelsize': 24, 'xtick.labelsize':20, 'ytick.labelsize':20, 'legend.fontsize':20, 'figure.facecolor': 'white'} sns.set(rc={'figure.figsize':(32,18)}) sns.set_theme(style = 'ticks', font = 'Calibri', rc = cust) sns.set_context('poster') colour = 'colorblind' # 交换hue和style变量:Shorthand对应颜色,Subscale对应形状 fig1 = sns.scatterplot(data = passframe, x = 'Slope1', y = 'Intercept1', hue = 'Shorthand', style = 'Subscale', s = 400, palette = colour, legend = 'full') # 提取图例手柄与标签,调整形状与颜色的关联 handles, labels = fig1.get_legend_handles_labels() # 定位Subscale图例的起始索引 index_style_title = labels.index('Subscale') # 构建形状映射字典:Subscale对应标记形状 style_dict = {label: handle.get_marker() for handle, label in zip(handles[1:index_style_title], labels[1:index_style_title])} # 遍历颜色条目(Shorthand),分配对应Subscale的形状 for handle, label in zip(handles[index_style_title + 1:], labels[index_style_title + 1:]): handle.set_marker(style_dict[subscale_dict[label]]) # 更新图例,仅保留Shorthand相关条目 fig1.legend(handles[index_style_title + 1:], labels[index_style_title + 1:], title='Data', loc = 'best', markerscale = 2, labelspacing = 1.2, fontsize = 24, title_fontsize = 32) # 设置坐标轴标签和范围 fig1.set_xlabel('$Slope (cm^{-1})$') fig1.set_ylabel('$Intercept (cm^{-4})$') plt.xlim([min(passframe['Slope1']), 1500]) plt.ylim([min(passframe['Intercept1']-2), max(passframe['Intercept2'])+2]) plt.show()
代码说明
- 交换
hue和style参数后,每个Shorthand条目对应唯一颜色,每个Subscale对应唯一形状,解决原图表颜色占比失衡的问题 - 通过
style_dict提取Subscale对应的标记形状,再将其分配给对应的Shorthand图例条目,实现形状与颜色的关联 - 保留原有的配色方案(色弱友好的
colorblind调色板)和布局配置,确保图表可读性与专业性
内容的提问来源于stack exchange,提问作者Aristle Monteiro
相关产品推荐
相关产品推荐

