英文:
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.plot
和 kind='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()
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论