如何根据名称为所有子图中的所有条形着色

How to color all bars in all subplots based off a name

提问人:Lasse Freitag 提问时间:11/15/2023 最后编辑:Trenton McKinneyLasse Freitag 更新时间:11/16/2023 访问量:76

问:

目标是用与其他条不同的颜色用“?”标记每个条形。之前已经问过类似的问题,但它并不能解决我在这里面临的问题。

如何根据名称为单个条形图着色

%matplotlib inline

import pandas as pd
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
import seaborn as sns

data=[['a','a','b'],[20,'?',18],['?','?','f'],['?','f','f'],['a','a','?']]
col_with_missting_values=['A1','A2','A3']
df=pd.DataFrame(data,columns=col_with_missting_values)

def color(coln):
    if coln=='?':
        return 'b'
    else:
        return 'r'

fig, axes = plt.subplots(1, len(col_with_missting_values), figsize=(20, 5))
for colname, ax in zip(col_with_missting_values, axes):
    (
        cr:=[color(x) for x in df[colname]],
        sns.countplot(df, x=f"{colname}", ax=ax, palette=cr),
        ax.set_xticklabels(ax.get_xticklabels(), rotation=90),
    )

每个带有“?”的 Bar 都应该是蓝色的,但不是,而 A2 中的 f 是蓝色的,这也是错误的

python pandas matplotlib seaborn 条形图

评论


答:

1赞 kevin41 11/15/2023 #1

问题在于,您正在将颜色映射到列中的每个值,但值可能会出现多次。例如,如果硬编码,则会看到结果是 .A2cr:=[color(x) for x in df[colname]]['r', 'b', 'b', 'r', 'r']

但是,您只有 3 个条形,因此仅使用前 3 个颜色值。这就是为什么您会看到 的蓝色 。如果我们只使用列的唯一值来创建颜色映射表,那么列的颜色将按预期进行。fA2

更改为cr:=[color(x) for x in df[colname]]cr:=[color(x) for x in df[colname].unique()],

结果:enter image description here

评论

0赞 Trenton McKinney 11/16/2023
不指定色调而传递调色板已弃用,并将在 v0.14.0 中删除。将 x 变量分配给 hue 并设置 legend=False 以获得相同的效果。
1赞 Trenton McKinney 11/16/2023 #2
  • 不传递而不传递已弃用,因此最好使用 pandas 将 DataFrame 转换为长格式。DataFrame.melt,并为颜色添加一列,该列提供了一列,以便轻松创建 的 和 的列。palettehuedictpalettehue
  • python v3.12.0pandas v2.1.2matplotlib v3.8.1seaborn v0.13.0 中测试。
import pandas as pd
import seaborn as sns
import numpy as np

# sample data from OP
data = [['a', 'a', 'b'], [20, '?', 18], ['?', '?', 'f'],
        ['?', 'f', 'f'], ['a', 'a', '?']]
cols = ['A1', 'A2', 'A3']
df = pd.DataFrame(data, columns=cols)

# convert the data to long form as required by seaborn
dfm = df.melt(var_name='variable', value_name='value')

# add a palette column
dfm['palette'] = np.where(dfm['value'].eq('?'), 'b', 'r')

# create a palette dictionary
palette = dict(dfm[['value', 'palette']].values)

# plot the data
g = sns.catplot(kind='count', data=dfm, x='value', col='variable', sharex=False,
                hue='value', palette=palette, legend=False, height=5, aspect=1)

# remove 'variable = ' from facet title if preferred
g.set_titles(template='{col_name}')

# remove xlabels if preferred
g.set(xlabel='')

# rotate xticklabels if preferred
_ = g.set_xticklabels(rotation=30)

enter image description here

dfm.head()

  variable value palette
0       A1     a       r
1       A1    20       r
2       A1     ?       b
3       A1     ?       b
4       A1     a       r

palette

{'a': 'r', 20: 'r', '?': 'b', 'f': 'r', 'b': 'r', 18: 'r'}