如何在Seaborn计数图中仅展示对应类别下有数据的文凭?
解决Seaborn Catplot子图仅显示对应职业存在的文凭问题
你的问题核心在于:Seaborn的catplot默认会使用整个数据集的所有文凭类别来生成每个子图,哪怕某个职业根本没有该文凭的记录,所以才会出现无关文凭显示的情况。而你之前尝试的query写法不仅语法有误(query里不需要加df[],直接用列名即可),而且逻辑上是全局筛选,无法实现按职业分组筛选的需求。
下面是实现每个子图仅显示对应职业存在文凭的完整解决方案:
步骤1:自定义FacetGrid绘制子图
我们需要用FacetGrid替代catplot,这样可以完全控制每个子图的数据源,只绘制当前职业下有数据的文凭:
import pandas as pd import seaborn as sns import matplotlib.pyplot as plt # 假设你的数据框已经定义好 df = pd.DataFrame({ 'function': ['nurse', 'doctor', 'paediatric_nurse','kitchen_staff','surgeon'] * 7, 'diploma': ['nurse_schoolA', 'doctor_schoolA', 'paed_nurse_schoolA', 'kitchen_certA', 'surgeon_schoolA', 'nurse_schoolB', 'doctor_schoolB', 'paed_nurse_schoolB', 'kitchen_certB', 'surgeon_schoolB', 'nurse_schoolC', 'doctor_schoolC', 'paed_nurse_schoolC', 'kitchen_certC', 'surgeon_schoolC', 'nurse_schoolD', 'doctor_schoolD', 'paed_nurse_schoolD', 'kitchen_certD', 'surgeon_schoolD', 'nurse_schoolE', 'doctor_schoolE', 'paed_nurse_schoolE', 'kitchen_certE', 'surgeon_schoolE', 'nurse_schoolF', 'doctor_schoolF', 'paed_nurse_schoolF', 'kitchen_certF', 'surgeon_schoolF', 'nurse_schoolG', 'doctor_schoolG', 'paed_nurse_schoolG', 'kitchen_certG', 'surgeon_schoolG'] }) # 创建FacetGrid,按function分栏,每行显示2个子图(可根据需求调整) g = sns.FacetGrid(df, col='function', col_wrap=2, height=4) # 定义每个子图的绘制函数 def plot_profession_diplomas(**kwargs): # 获取当前子图对应的职业 current_profession = kwargs['data']['function'].iloc[0] # 筛选该职业的所有数据 subset = df[df['function'] == current_profession] # 统计该职业下各文凭的计数 diploma_counts = subset['diploma'].value_counts().reset_index() diploma_counts.columns = ['diploma', 'count'] # 绘制水平条形图 sns.barplot(data=diploma_counts, y='diploma', x='count', palette='viridis', **kwargs) # 将绘制函数映射到每个子图 g.map_dataframe(plot_profession_diplomas) # 美化布局和标题 g.set_titles(col_template='{col_name}') # 设置子图标题为对应职业名称 g.fig.autofmt_xdate(rotation=45) # 旋转x轴标签避免重叠 plt.tight_layout() plt.show()
代码解释
- FacetGrid初始化:
col='function'指定按职业分栏,col_wrap=2控制每行显示2个子图,避免子图过于拥挤。 - 自定义绘制函数:
- 先获取当前子图对应的职业,筛选出该职业的数据集;
- 用
value_counts()统计该职业下每个文凭的数量; - 用
sns.barplot绘制水平条形图(注意这里用y='diploma'、x='count'实现水平方向)。
- 布局调整:
set_titles设置子图标题,autofmt_xdate旋转x轴标签,tight_layout优化整体布局。
为什么你的原代码不行?
你之前的df.query("df['diploma'].count()>0")存在两个问题:
query语法错误:在query中直接使用列名即可,不需要加df[],正确写法应该是query("diploma.notna()"),但这也只是全局筛选非空文凭,不是按职业分组筛选;- 逻辑错误:
catplot的data参数是全局数据集,即使你做了全局筛选,它依然会使用所有文凭类别来生成子图,无法实现按职业动态显示对应文凭的需求。
内容的提问来源于stack exchange,提问作者Lysis90
相关产品推荐
相关产品推荐

