如何修改seaborn stripplot图例中的marker标记形状
Seaborn stripplot自定义marker后图例标记不匹配问题解决
问题描述
使用seaborn绘制stripplot时,分别为两组数据设置了三角形(^)和菱形(D)作为marker,但生成的图例仅显示彩色圆形,未匹配设置的标记形状。
可复现问题代码
import pandas as pd import numpy as np import seaborn as sns import matplotlib.pyplot as plt letters = list('abcdefghijklmnopqrstuvwxyz') place = ['North', 'South', 'East', 'West'] letter_set1 = set("abcdefghijklmn") letter_set2 = set("opqrstuvwxyz") data_size = 100 df_dict = {'letter': np.random.choice(letters, data_size), 'place': np.random.choice(place, data_size), "height": np.random.randint(low=40, high=100, size=data_size), "weight": np.random.randint(low=150, high=210, size=data_size),} df = pd.DataFrame(df_dict) print(df) fig, ax = plt.subplots(1, 1, figsize=(10, 7)) # 此处violinplot可以忽略 sns.violinplot(x='place', y="weight", data=df, scale="width", inner="quartile", bw=0.2, linewidth=1, ) for violin in ax.collections: violin.set_alpha(0.1) set1_df = df[df['letter'].isin(letter_set1)] set2_df = df[df['letter'].isin(letter_set2)] sns.stripplot(data=set1_df, x='place', y="weight", hue="letter", palette="Set1", size=10, linewidth=0.05, marker='^', ax=ax ) sns.stripplot(data=set2_df, x='place', y="weight", hue="letter", palette="Set2", size=10, linewidth=0.05, marker='D', ax=ax ) # 调整图例顺序 handles, labels = ax.get_legend_handles_labels() zipped_list = zip(handles, labels) sorted_zipped_list = sorted(zipped_list, key=lambda x: x[1]) ordered_handles, ordered_labels = [x[0] for x in sorted_zipped_list], [x[1] for x in sorted_zipped_list] ax.legend( handles=ordered_handles, labels=ordered_labels, title="Letter", bbox_to_anchor=(1.02, 1), loc="upper left", ) plt.tight_layout() plt.show() plt.close()
问题现象
输出效果如下图所示,图例中所有标记均为默认圆形,没有对应上自定义的三角形和菱形:
解决方法
可以直接修改PathCollection类型图例句柄的marker属性,不需要重新构造图例。在获取ordered_handles之后、调用ax.legend之前,加入标记样式修改代码即可,完整的图例设置部分如下:
# 更新图例顺序 handles, labels = ax.get_legend_handles_labels() zipped_list = zip(handles, labels) sorted_zipped_list = sorted(zipped_list, key=lambda x: x[1]) ordered_handles, ordered_labels = [x[0] for x in sorted_zipped_list], [x[1] for x in sorted_zipped_list] # 新增:按分组修改每个句柄的marker样式 for handle, label in zip(ordered_handles, ordered_labels): handle.set_marker('^' if label in letter_set1 else 'D') ax.legend( handles=ordered_handles, labels=ordered_labels, title="Letter", bbox_to_anchor=(1.02, 1), loc="upper left", )
该方法直接调用matplotlib PathCollection原生的set_marker方法修改实例属性,无需额外引入依赖,修改后图例标记会和stripplot设置的自定义标记完全对应。
内容的提问来源于stack exchange,提问作者LanternD
相关产品推荐
相关产品推荐

