pandas 如何根据百分比绘制条形图并使用值进行注解

6ojccjat  于 2023-04-18  发布在  其他
关注(0)|答案(2)|浏览(175)

我无法将条形图的高度扩展到它们的百分比,我该怎么做?我越来越困惑了...
我不想看到条形图的百分比,我想要的是值(40,40,40,40,40,33,17)。
我想要7个条形图,它们的高度是百分比,但是条形图上的容器应该有它们的值名称。第一个条形的值为40。因此,此条形顶部应位于%100水平,但容器必须写为40。
另一个例子;最后一个(Tiktok bar)bar的值为17,因此容器应该显示17,但该bar应该位于%42.5的高度

DataFrame和导入示例

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import matplotlib.ticker as mtick

plt.figure(figsize=(18,11),dpi=100)
sns.set_theme (style="whitegrid", palette="tab20b")

x_ekseni= ['İlgili Sosyal Medya Hesapları']
Website= [40]
Twitter= [40]
Facebook= [40]
Instagram= [40]
Youtube= [40]
Linkedin= [33]
Tiktok= [17]

index=x_ekseni

df = pd.DataFrame({'Website': Website,
               'Twitter': Twitter,
               'Facebook': Facebook,
               'Instagram': Instagram,
               'Youtube': Youtube,
               'Linkedin': Linkedin,
               'Tiktok': Tiktok}, index=index)

df

Website  Twitter  Facebook  Instagram  Youtube  Linkedin  Tiktok
İlgili Sosyal Medya Hesapları       40       40        40         40       40        33      17

Plot

ax = df.plot.bar(stacked=False,edgecolor='white',width = 2.5,linewidth=0.5)

# iterate through the containers
for c in ax.containers:

    # get the current segment label (a string); corresponds to column / legend
    col = c.get_label()

    labels = df[col].replace(0, '')

    # add the annotation
    ax.bar_label(c, labels=labels, label_type='center', fontweight='bold', color='white',fontsize=10)

plt.title("İstanbul'daki Belediyelerin Sosyal Medya Kullanımı", fontsize=11, fontweight=0,        color="black", loc="center")

ax.set_ylabel("İldeki Tüm Belediyeler İçinde Yüzde (n=40)", fontsize= 10)

ax.yaxis.set_major_formatter(mtick.PercentFormatter())

plt.xticks(rotation=0,fontsize=8)
plt.yticks(rotation=0,fontsize=8)
plt.ylim(0,100)

ax.legend(frameon=True, fontsize=8)

fdx2calv

fdx2calv1#

*python 3.11.2pandas 2.0.0matplotlib 3.7.1seaborn 0.12.2中测试

  • 应该注意的是,OP中的图是一组条形图,这就是为什么只有一个刻度。
  • 为了使条形图具有其各自百分比值的高度,计算并添加一个包含百分比值的新列,用新列绘制条形图,并将实际值传递给.bar_label中的labels=参数。

导入和DataFrame

import pandas as pd
import matplotlib.ticker as tkr
import matplotlib.pyplot as plt
import seaborn as sns

# test dataframe
data = {'Website': [40], 'Twitter': [40], 'Facebook': [40], 'Instagram': [40], 'Youtube': [40], 'Linkedin': [33], 'Tiktok': [17]}
df = pd.DataFrame(data, index=['İlgili Sosyal Medya Hesapları'])

# transpose df from a wide to a long form
df = df.T

# add a percent column
df['per'] = df.div(df.sum()).mul(100).round(2)

df

İlgili Sosyal Medya Hesapları   per
Website                               40  16.0
Twitter                               40  16.0
Facebook                              40  16.0
Instagram                             40  16.0
Youtube                               40  16.0
Linkedin                              33  13.2
Tiktok                                17   6.8

使用pandas.DataFrame.plotkind='bar'绘图

# plot percent column 
ax = df.plot(kind='bar', y='per', rot=0, figsize=(10, 7), ylabel='', legend=False)

# add the annotations; there's only 1 container of 7 artists
# iterating through the containers is only necessary for grouped or stacked bars, which have multiple containers
ax.bar_label(ax.containers[0], labels=df['İlgili Sosyal Medya Hesapları'].replace(0, ''), label_type='center', fontweight='bold', color='white', fontsize=10)

ax.set_title("İstanbul'daki Belediyelerin Sosyal Medya Kullanımı", fontsize=11, fontweight=0, color="black", loc="center")

ax.set_ylabel("İldeki Tüm Belediyeler İçinde Yüzde (n=40)", fontsize= 10)
ax.set_xlabel(df.columns[0], fontsize= 10)

ax.yaxis.set_major_formatter(tkr.PercentFormatter())

ax.tick_params(axis='both', which='major', labelsize=8)
_ = ax.set_ylim(0, 100)

使用seaborn.barplot绘图

plt.figure(figsize=(10, 7))

# plot df, but the index must be reset
ax = sns.barplot(data=df.reset_index(), x='index', y='per')

ax.bar_label(ax.containers[0], labels=df['İlgili Sosyal Medya Hesapları'].replace(0, ''), label_type='center', fontweight='bold', color='white', fontsize=10)

ax.set_title("İstanbul'daki Belediyelerin Sosyal Medya Kullanımı", fontsize=11, fontweight=0, color="black", loc="center")

ax.set_ylabel("İldeki Tüm Belediyeler İçinde Yüzde (n=40)", fontsize= 10)
ax.set_xlabel(df.columns[0], fontsize= 10)

ax.yaxis.set_major_formatter(tkr.PercentFormatter())

ax.tick_params(axis='both', which='major', labelsize=8)
_ = ax.set_ylim(0, 100)

注意事项

  • 根据从注解添加到OP的其他信息进行更新,其中百分比是根据特定值n=40计算的,使用以下内容计算'per'列。
  • 前面代码中的其他内容都不需要更改。
# an arbitrary value
n = 40
df['per'] = df.div(n, axis=0).mul(100).round(2)

# or

# the max value in the column
df['per'] = df.div(df.iloc[:, 0].max(), axis=0).mul(100).round(2)
İlgili Sosyal Medya Hesapları    per
Website                               40  100.0
Twitter                               40  100.0
Facebook                              40  100.0
Instagram                             40  100.0
Youtube                               40  100.0
Linkedin                              33   82.5
Tiktok                                17   42.5

ndasle7k

ndasle7k2#

要显示堆叠条形图中每个条形顶部的百分比值,可以使用matplotlib提供的bar_label函数。

for container in ax.containers:
    ax.bar_label(container, labels=[f'{h:.0f}%' if h > 0 else '' for h in container.datavalues], label_type='edge')

完整代码:

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import matplotlib.ticker as mtick

plt.figure(figsize=(18,11),dpi=100)
sns.set_theme (style="whitegrid", palette="tab20b")

x_ekseni= ['İlgili Sosyal Medya Hesapları']
Website= [40]
Twitter= [40]
Facebook= [40]
Instagram= [40]
Youtube= [40]
Linkedin= [33]
Tiktok= [17]

index=x_ekseni

df = pd.DataFrame({'Website': Website,
               'Twitter': Twitter,
               'Facebook': Facebook,
               'Instagram': Instagram,
               'Youtube': Youtube,
               'Linkedin': Linkedin,
               'Tiktok': Tiktok}, index=index)

ax = df.plot.bar(stacked=False, edgecolor='white', width=2.5, linewidth=0.5)

for container in ax.containers:
    ax.bar_label(container, labels=[f'{h:.0f}%' if h > 0 else '' for h in container.datavalues], label_type='edge')

plt.title("İstanbul'daki Belediyelerin Sosyal Medya Kullanımı", fontsize=11, fontweight=0, color="black", loc="center")

ax.set_ylabel("İldeki Tüm Belediyeler İçinde Yüzde (n=40)", fontsize=10)

ax.yaxis.set_major_formatter(mtick.PercentFormatter())
plt.xticks(rotation=0, fontsize=8)
plt.yticks(rotation=0, fontsize=8)
plt.ylim(0, 100)

ax.legend(frameon=True, fontsize=8)

plt.show()

相关问题