如何用Seaborn为DataFrame中每个唯一name生成多hue折线图?
解决Seaborn折线图按name分图、hue区分多列分数的问题
首先看你的原始数据结构:
name,id,score1,score2,score3 ax,1,32,43,32 sy,1,34,22,22 ax,2,22,6,8 ax,3,10,5,4 bz,1,22,2,2 sy,2,10,1,0 bz,2,9,8,1
你需要的效果是每个name对应一个子图,x轴为id,y轴为分数值,用hue区分三个分数列。核心问题是Seaborn的hue需要对应数据中的一列分类值,但你的分数分散在多列,所以第一步要把宽表转成适合Seaborn的长表格式。
具体步骤
- 数据格式转换:用
pandas.melt()把多个分数列合并成两列——一列标记分数类型(score1/score2/score3),一列存储对应分数值。 - 分面绘图:用
seaborn.FacetGrid按name拆分子图,再在每个子图里绘制折线图,指定x、y和hue对应转换后的列。
完整代码
import pandas as pd import seaborn as sns import matplotlib.pyplot as plt # 读取数据(如果是从csv文件读取,替换为pd.read_csv('your_file.csv')) data = pd.DataFrame({ 'name': ['ax', 'sy', 'ax', 'ax', 'bz', 'sy', 'bz'], 'id': [1, 1, 2, 3, 1, 2, 2], 'score1': [32, 34, 22, 10, 22, 10, 9], 'score2': [43, 22, 6, 5, 2, 1, 8], 'score3': [32, 22, 8, 4, 2, 0, 1] }) # 宽表转长表:保留name和id作为标识列,合并score1/2/3为长格式 melted_data = pd.melt( data, id_vars=['name', 'id'], # 不需要转换的列 value_vars=['score1', 'score2', 'score3'], # 要合并的分数列 var_name='score_type', # 新的分类列名(标记分数类型) value_name='score_value' # 新的数值列名(存储分数值) ) # 创建分面网格,按name拆分子图,共享x/y轴刻度 g = sns.FacetGrid(melted_data, col='name', sharex=True, sharey=True) # 在每个子图绘制折线图,指定x、y、hue对应列 g.map(sns.lineplot, 'id', 'score_value', 'score_type', marker='o') # 添加图例(FacetGrid默认不自动生成,手动补充) g.add_legend(title='Score Type') # 调整布局避免标签重叠 plt.tight_layout() plt.show()
代码说明
pd.melt()是核心操作:将原本每行对应一组name+id+三个分数的宽表,转成每行对应一组name+id+一个分数类型+对应值的长表,让Seaborn的hue能通过score_type列区分不同线条。FacetGrid(col='name')会自动为每个唯一的name生成独立子图,sharex/sharey参数保证子图轴刻度一致,便于对比不同name的分数变化。map()方法将lineplot应用到每个子图,参数依次对应x、y、hue的列名。
内容的提问来源于stack exchange,提问作者nerd
相关产品推荐
相关产品推荐

