提问人:Jonathan Ng 提问时间:11/17/2023 最后编辑:Trenton McKinneyJonathan Ng 更新时间:11/20/2023 访问量:31
如何在没有类别数据的情况下用 0 计数注释柱线
How to annotate bars with 0 counts when there's no data for the category
问:
我有使用 seaborn 的代码,将分类图绘制到 FacetGrid 上。我在函数中使用了 a,因此使用 .中的参数设置为变量,在此上下文中定义为 。 是 my 中的一列,顾名思义,它代表年龄类别。这是一个有序的 pandas 分类 dtype。catplot
countplot
catplot
kind='count'
col
catplot
col_cat
age_category
age_category
df
我的如下:df
ipdb> df
spirometryResult_category age_category habits-smoking
_id
63bb97708e5f58ef85f6e4ea Normal 20-39 years old Yes
63bd1b228e5f58ef85f73130 Normal 20-39 years old Yes
6423cb1c174e67af0aa0f0fc Normal 20-39 years old No
6423d85e174e67af0aa10cda Restrictive 20-39 years old No
6423d8bb174e67af0aa10d98 Obstructive 20-39 years old No
... ... ... ...
6549a0df0941d048fdfd94c4 Obstructive 20-39 years old No
6549d0ab0941d048fdfd960d Normal 40-59 years old No
6549d0ee0941d048fdfd962b Normal 20-39 years old No
654b17a20941d048fdfda256 Normal 20-39 years old No
654d81700941d048fdfdc27d Normal 40-59 years old No
[106 rows x 3 columns]
中的列如下所示:age_category
df
ipdb> df['age_category']
_id
63bb97708e5f58ef85f6e4ea 20-39 years old
63bd1b228e5f58ef85f73130 20-39 years old
6423cb1c174e67af0aa0f0fc 20-39 years old
6423d85e174e67af0aa10cda 20-39 years old
6423d8bb174e67af0aa10d98 20-39 years old
...
6549a0df0941d048fdfd94c4 20-39 years old
6549d0ab0941d048fdfd960d 40-59 years old
6549d0ee0941d048fdfd962b 20-39 years old
654b17a20941d048fdfda256 20-39 years old
654d81700941d048fdfdc27d 40-59 years old
Name: age_category, Length: 106, dtype: category
Categories (4, object): ['20-39 years old' < '40-59 years old' < '60-79 years old' < '>= 80 years old']
栏目中类别的分布如下:age_category
ipdb> df['age_category'].value_counts()
age_category
20-39 years old 89
40-59 years old 14
60-79 years old 3
>= 80 years old 0
Name: count, dtype: int64
“>= 80 岁”年龄类别中的受试者数量为 0,这让我在绘制条形图注释时遇到了问题。
通常,下面的代码有效。我的目标是绘制多个子图,每个年龄组一个子图,显示 和 的每个组合的主题计数。spirometryResult_category
habits-smoking
# Getting colours as specified in the config, for each hue category
# Need to remove this hardcoding when i improve script
colour_map = config['seaborn_colourmaps'][hue_cat]
# Plotting graph
# count refers to param_category counts
plt.subplots(figsize=figsize)
# Not sure why setting axes.labelsize here doesnt
# work
sns.set_context('paper', rc={'font.size':fontsize})
# height=4, aspect=.6,
g = sns.catplot(
data=df, x=param_category, hue=hue_cat, col=col_cat,
kind='count', palette=colour_map, col_wrap=wrap_num,
saturation=1
)
for ax in g.axes:
ax.tick_params(left=False, labelbottom=True)
ax.set_xticklabels(ax.get_xticklabels(), size=fontsize)
# Replacing subplot title if needed
if col_cat in config['seaborn_alt_names']:
new_title = config['seaborn_alt_names'][col_cat]
ax.set_title( ax.get_title().replace(col_cat, new_title), size=fontsize)
# Auto-label bars
for container in ax.containers:
container.datavalues = np.nan_to_num(container.datavalues)
ax.bar_label(container, fmt='%.0f', padding=2)
# In contrast to prev plotting code, despine goes here, as facetgrid
# requires it to be done this way
g.despine(top=True, right=True, left=True)
# Fine adjustment of aesthetics
g.set(yticklabels=[], ylabel=None, xlabel=None)
g.tick_params('x', rotation=90)
# Checking if legend title is needed
legend = False
if 'legend' in plot_info:
legend = plot_info['legend']
if not legend:
g.get_legend().set_title(None)
else:
# If an alternative legend title is specified,
# use that, if not, use the default one
if hue_cat in config['seaborn_alt_names']:
new_title = config['seaborn_alt_names'][hue_cat]
g.legend.set_title(new_title)
# Continuing adjustment of aesthetics
plt.subplots_adjust(hspace=1, wspace=0.3)
g.figure.savefig(filename, bbox_inches='tight')
plt.close()
输出图片如下所示:
如您所见,“>= 80 岁”的类别没有主题,因此对于其相应的子图,根本没有绘制文本“0”。所有其他年龄类别都正确创建了相应的条形图和注释。对于这种情况,其中“>= 80 岁”没有主题,是一个空列表,因此我的 for 循环用于注释计数为 0 的案例不起作用。ax.containers
for container in ax.containers:
在这种情况下,我如何强制 seaborn 在正确的位置(由 seaborn 自动决定,因此我不必对任何内容进行硬编码)注释 0 计数的子图,其中类别有 0 个主题,并且是一个空列表?ax.containers
答:
0赞
Trenton McKinney
#1
- 如许多问题所示,包括 Seaborn 显示 Pandas 列中未找到的值,请使用
pandas。Series.cat.remove_unused_categories
在打印之前删除空类别。
import seaborn as sns
# sample data
df = sns.load_dataset('titanic')
# add categories
df['age_cat'] = pd.cut(x=df.age, bins=range(0, 91, 10), ordered=True)
# remove unused categories
df['age_cat'] = df['age_cat'].cat.remove_unused_categories()
g = sns.catplot(kind='count', data=df, x='embark_town', hue='sex', col='age_cat', col_wrap=3, height=2.5, aspect=2)
axes = g.axes.flat
for ax in axes:
for c in ax.containers:
ax.bar_label(c, fmt='%.0f', padding=2)
没有df['age_cat'].cat.remove_unused_categories()
评论
1赞
Jonathan Ng
11/22/2023
非常感谢!最终,我选择了另一种解决方案,因为我的同事们更喜欢我以 0 个计数显示子图,但删除 x 轴及其相关的标签和刻度,并添加一个短语,说由于没有主题,因此没有绘制柱线。但是,我认为您的解决方案很好,如果我使用的方法不起作用,则可以使用=)
评论