如何绘制百分比柱状图并用数值注释。

huangapple go评论83阅读模式
英文:

How to plot bars against percent and annotate with the value

问题

I couldn't expand bars height to their percentage how can I do that? I'm getting confused...

我无法将条形图的高度扩展到它们的百分比,该如何做到?我感到困惑...

I don't want to see the percentages of the bars, I want the values (40,40,40,40,40,33,17).

我不想看到条形图的百分比,我想要数值(40,40,40,40,40,33,17)。

I want 7 bars with height of their percentage, but containers on bars should have their value name. For example n=40 in my problem; First bar has the value of 40. So this bars top should at %100 level, but container must wrote as 40.

我希望有7个高度为其百分比的条形图,但条形图上的容器应该带有它们的值名称。例如,在我的问题中,n=40;第一根条形图的值为40。因此,这些条形图的顶部应该在100%水平,但容器上必须写成40。

Also another example; last (Tiktok bar) bar has the value of 17 so container should say 17 but the bar should be at the height of %42.5.

还有另一个例子;最后(Tiktok条形图)的条形图的值为17,所以容器应该显示17,但条形图的高度应为42.5%。

英文:

I couldn't expand bars height to their percentage how can I do that? I'm getting confused...

I don't want to see the percentages of the bars, I want the values (40,40,40,40,40,33,17).

I want 7 bars with height of their percentage, but containers on bars should have their value name. For example n=40 in my problem; First bar has the value of 40. So this bars top should at %100 level, but container must wrote as 40.

Also another example; last (Tiktok bar) bar has the value of 17 so container should say 17 but the bar should be at the height of %42.5

Sample DataFrame and Imports

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)

如何绘制百分比柱状图并用数值注释。

答案1

得分: 2

  • python 3.11.2, pandas 2.0.0, matplotlib 3.7.1, seaborn 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

# 测试数据框
data = {'网站': [40], 'Twitter': [40], 'Facebook': [40], 'Instagram': [40], 'Youtube': [40], 'Linkedin': [33], 'Tiktok': [17]}
df = pd.DataFrame(data, index=['相关社交媒体帐户'])

# 将数据框从宽格式转换为长格式
df = df.T

# 添加百分比列
df['百分比'] = df.div(df.sum()).mul(100).round(2)

df

           相关社交媒体帐户   百分比
网站                 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' 绘制图表

# 绘制百分比列
ax = df.plot(kind='bar', y='百分比', rot=0, figsize=(10, 7), ylabel='', legend=False)

# 添加标注;只有一个包含 7 个艺术家的容器
# 只需要在容器之间进行迭代,以便在分组或堆叠柱形图中有多个容器时才需要
ax.bar_label(ax.containers[0], labels=df['相关社交媒体帐户'].replace(0, ''), label_type='center', fontweight='bold', color='white', fontsize=10)

ax.set_title("伊斯坦布尔市政府的社交媒体使用", fontsize=11, fontweight=0, color="black", loc="center")

ax.set_ylabel("在市内所有市政府中的百分比 (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))

# 绘制 df,但索引必须重置
ax = sns.barplot(data=df.reset_index(), x='index', y='百分比')

ax.bar_label(ax.containers[0], labels=df['相关社交媒体帐户'].replace(0, ''), label_type='center', fontweight='bold', color='white', fontsize=10)

ax.set_title("伊斯坦布尔市政府的社交媒体使用", fontsize=11, fontweight=0, color="black", loc="center")

ax.set_ylabel("在市内所有市政府中的百分比 (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 计算,请使用以下方法计算 百分比 列。
  • 先前代码中的其他内容无需更改。
# 一个任意值
n = 40
df['百分比'] = df.div(n, axis=0).mul(100).round(2)

# 或

# 列中的最大值
df['百分比'] = df.div(df.iloc[:, 0].max(), axis=0).mul(100).round(2)
           相关社交媒体帐户    百分比
网站                 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

[![使用 pandas.DataFrame.plot 绘制的图表][6]][6]

[![使用 seaborn.barplot 绘制的图表][7]][7]

英文:
  • Tested in python 3.11.2, pandas 2.0.0, matplotlib 3.7.1, seaborn 0.12.2
  • Note the plot in the OP is a single group of bars, which is why there's only one tick.
  • In order to have the bars be the height of their respective percent value, calculate and add a new column with the percent value, plot the bars with the new column, and pass the actual values to the labels= parameter in .bar_label.

Imports and 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

Plot using pandas.DataFrame.plot with kind='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)

如何绘制百分比柱状图并用数值注释。

Plot using 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)

如何绘制百分比柱状图并用数值注释。

Note

  • Updated based on additional information added to the OP from a comment, where the percent is calculated against a specific value, n=40, use the following to calculate the 'per' column.
  • Nothing else in the previous code needs to change.
# 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

[![plotted with pandas.DataFrame.plot][6]][6]

[![plotted with seaborn.barplot][7]][7]

[6]: https://i.stack.imgur.com/zl0df.png "plotted with pandas.DataFrame.plot"
[7]: https://i.stack.imgur.com/goajF.png "plotted with seaborn.barplot"

答案2

得分: 0

为了在堆叠条形图的每个条形上方显示百分比数值您可以使用matplotlib提供的bar_label函数

```python
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 = ['相关社交媒体账户']
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("伊斯坦布尔市政府的社交媒体使用", fontsize=11, fontweight=0, color="black", loc="center")

ax.set_ylabel("在市内所有市政府中的百分比(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()
英文:

To display the percentage values on top of each bar in your stacked bar chart, you can use the bar_label function provided by matplotlib.

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')

Complete code :

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()

huangapple
  • 本文由 发表于 2023年4月17日 17:19:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/76033552.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定