为多列绘制多个条形图

Posted

技术标签:

【中文标题】为多列绘制多个条形图【英文标题】:Plot multiple bar plots for multiple columns 【发布时间】:2021-11-03 00:24:30 【问题描述】:

我有一个大致如下表的数据集。 我需要为TS1TS5 的每一列创建一个条形图,计算该列中每个项目的数量。这些项目是以下之一:NOT_SEEN NOT_ABLE HIGH_BAR110140 之间的数值,用 2 分隔(所以 110112114 等)。

我找到了一种方法可以很好地做到这一点,但我要问的是是否有一种方法可以创建循环或其他东西,所以我不必复制粘贴相同的代码 5 次(对于 5 列)?

这是我尝试过的工作:

num_range = list(range(110,140, 2))
OUTCOMES = ['NOT_SEEN', 'NOT_ABLE', 'HIGH_BAR']
OUTCOMES.extend([str(num) for num in num_range])
OUTCOMES = CategoricalDtype(OUTCOMES, ordered = True)

fig, ax =plt.subplots(2, 3, sharey=True)
fig.tight_layout(pad=3)

这是我复制 5 次的内容,只更改了标题(Testing 1Testing 2 等)和TS1TS2..(在第一行)。

df["outcomes"] = df["TS1"].astype(OUTCOMES)
bpt=sns.countplot(x= "outcomes", data=df, palette='GnBu', ax=ax[0,0])
plt.setp(bpt.get_xticklabels(), rotation=60, size=6, ha='right')
bpt.set(xlabel='')
bpt.set_title('Testing 1')

那么下面的代码在上面的“5”个实例下面。

ax[1,2].set_visible(False)
plt.show()

我确信有一种更好的方法可以做到这一点,但我对这一切都很陌生。

另外,我需要确保条形图的条从左到右排列为:NOT_SEENNOT_ABLEHIGH_BAR110112114

使用 python 2.7(很遗憾不是我的选择)和 pandas 0.24.2。

+----+------+------+----------+----------+----------+----------+----------+
| ID | VIEW | YEAR | TS1      | TS2      | TS3      | TS4      | TS5      |
+----+------+------+----------+----------+----------+----------+----------+
| AA | NO   | 2005 |          | 134      |          | HIGH_BAR |          |
+----+------+------+----------+----------+----------+----------+----------+
| AB | YES  | 2015 |          |          | NOT_SEEN |          |          |
+----+------+------+----------+----------+----------+----------+----------+
| AB | YES  | 2010 | 118      |          |          |          | NOT_ABLE |
+----+------+------+----------+----------+----------+----------+----------+
| BB | NO   | 2020 |          |          |          |          |          |
+----+------+------+----------+----------+----------+----------+----------+
| BA | YES  | 2020 |          |          |          | NOT_SEEN |          |
+----+------+------+----------+----------+----------+----------+----------+
| AA | NO   | 2010 |          |          |          |          |          |
+----+------+------+----------+----------+----------+----------+----------+
| BA | NO   | 2015 |          |          |          |          | 132      |
+----+------+------+----------+----------+----------+----------+----------+
| BB | YES  | 2010 |          | HIGH_BAR |          | 140      | NOT_ABLE |
+----+------+------+----------+----------+----------+----------+----------+
| AA | YES  | 2020 |          |          |          |          |          |
+----+------+------+----------+----------+----------+----------+----------+
| AB | NO   | 2010 |          |          |          | 112      |          |
+----+------+------+----------+----------+----------+----------+----------+
| AB | YES  | 2015 |          |          | NOT_ABLE |          | HIGH_BAR |
+----+------+------+----------+----------+----------+----------+----------+
| BB | NO   | 2020 |          |          |          | 145      |          |
+----+------+------+----------+----------+----------+----------+----------+
| BA | NO   | 2015 |          | 110      |          |          |          |
+----+------+------+----------+----------+----------+----------+----------+
| AA | YES  | 2010 | HIGH_BAR |          |          | NOT_SEEN |          |
+----+------+------+----------+----------+----------+----------+----------+
| BA | YES  | 2015 |          |          |          |          |          |
+----+------+------+----------+----------+----------+----------+----------+
| AA | NO   | 2020 |          |          |          | 118      |          |
+----+------+------+----------+----------+----------+----------+----------+
| BA | YES  | 2015 |          | 180      | NOT_ABLE |          |          |
+----+------+------+----------+----------+----------+----------+----------+
| BB | YES  | 2020 |          | NOT_SEEN |          |          | 126      |
+----+------+------+----------+----------+----------+----------+----------+

【问题讨论】:

仅供参考:彻底回答问题非常耗时。如果您的问题已解决,请通过接受最适合您的需求的解决方案表示感谢。 位于答案左上角的 / 箭头下方。如果出现更好的解决方案,则可以接受新的解决方案。如果您有 15 岁以上的声誉,您也可以使用 / 箭头对答案的有用性进行投票。 如果解决方案不能回答问题,请发表评论。 What should I do when someone answers my question?。谢谢 【参考方案1】:

您可以将绘图线放在一个函数中,并在 for 循环中调用它,在每次迭代中自动更改列、标题和轴:

fig, axes =plt.subplots(2, 3, sharey=True)
fig.tight_layout(pad=3)

def plotting(column, title, ax):
    df["outcomes"] = df[column].astype(OUTCOMES)
    bpt=sns.countplot(x= "outcomes", data=df, palette='GnBu', ax=ax)
    plt.setp(bpt.get_xticklabels(), rotation=60, size=6, ha='right')
    bpt.set(xlabel='')
    bpt.set_title(title)

columns = ['TS1', 'TS2', 'TS3', 'TS4', 'TS5']
titles = ['Testing 1', 'Testing 2', 'Testing 3', 'Testing 4', 'Testing 5']

for column, title, ax in zip(columns, titles, axes.flatten()):
    plotting(column, title, ax)

axes[1,2].set_visible(False)

plt.show()

【讨论】:

【参考方案2】:

您可以使用seaborn.catplot 避免循环,这允许您将多个countplots 绘制到FacetGrid 上。

这是用 python 2.7.18 测试的(尽管它仍然适用于 python 3):

    meltTS数据转换成long form:

    melted = df.melt(id_vars=[], value_vars=['TS1','TS2','TS3','TS4','TS5'],
                     var_name='testing', value_name='outcome')
    
    #    testing outcome
    # 0      TS1     NaN
    # 1      TS1     NaN
    # 2      TS1     118
    # 3      TS1     NaN
    # ..     ...     ...
    # 88     TS5     NaN
    # 89     TS5     126
    

    通过catplot 绘制melted 数据:

    g = sns.catplot(kind='count', x='outcome', col='testing',
                    col_wrap=3, order=OUTCOMES.categories,
                    data=melted, palette='GnBu_r')
    g.set_xticklabels(rotation=90)
    


版本:

>>> sys.version
# 2.7.18 (default, Mar 15 2021, 14:29:03) \n[GCC 10.2.0]
>>> pandas.__version__
# 0.24.2
>>> matplotlib.__version__
# 2.2.5
>>> seaborn.__version__
# 0.9.1

【讨论】:

以上是关于为多列绘制多个条形图的主要内容,如果未能解决你的问题,请参考以下文章

matplotlib:在条形图上绘制多列熊猫数据框

在多列上分组时如何绘制条形图?

绘制多个条形图

绘制多个条形图

使用 ax.bar() 使用 matplotlib 绘制多个条形图

在同一轴上绘制多个条形图