pandas 如何在条形图的条形内显示值?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/44491583/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 03:45:56  来源:igfitidea点击:

How to show values inside the bars of a bargraph?

pythonpandasmatplotlib

提问by user517696

I have a dataframe like this:

我有一个这样的数据框:

                 platform     count
release_year        
         1996    PlayStation   138
         1997    PlayStation   170
         1998    PlayStation   155
         1999    PC            243...

Now I want to plot horizontal bargraph with the Platform name inside the respective bars such that it looks something like this:

现在我想在各自的条形内绘制带有平台名称的水平条形图,使其看起来像这样:

enter image description here

在此处输入图片说明

How do I do that?

我怎么做?

回答by David Jaimes

Here's the input data.csvfile once you find the percentage in each platform:

这是data.csv在每个平台中找到百分比后的输入文件:

Platform,Percent
Nintendo,34
PC,16
Playstation,28
Xbox,22

This is the code:

这是代码:

import pandas as pd
import matplotlib.pyplot as plt

df = pd.read_csv("data.csv", index_col=0)
df.plot(kind="barh", legend=False, width=0.8)
for i, (p, pr) in enumerate(zip(df.index, df["Percent"])):
    plt.text(s=p, x=1, y=i, color="w", verticalalignment="center", size=18)
    plt.text(s=str(pr)+"%", x=pr-5, y=i, color="w",
             verticalalignment="center", horizontalalignment="left", size=18)
plt.axis("off")
# xticks & yticks have empty lists to reduce white space in plot
plt.xticks([])
plt.yticks([])
plt.tight_layout()
plt.savefig("data.png")

enter image description here

在此处输入图片说明

回答by void

Not sure if you want it to be in Percentage %or as count numberitself. That's up to you to decide. However first convert your dataframe into a list using:

不确定您是希望它是百分比还是计数本身。这由你来决定。但是首先使用以下方法将您的数据框转换为列表:

count = df["count"].tolist()
platform = df["platform"].tolist()

I will not be focusing on that. You can find some help regarding that from

我不会专注于此。你可以从

Dataframe to list 1

要列出 1 的数据框

Dataframe to list 2

要列出 2 的数据框

Once you get the below list then,

一旦你得到下面的清单,

count = ['138','170','155','243','232']
platform =['PlayStation','PlayStation','PlayStation','PC','PlayStation']

Note: The above two would be your text labelsinside bar graphs.

注意:以上两个将是条形图中的文本标签

Here is the complete code:

这是完整的代码:

import matplotlib.pyplot as plt
from numpy.random import rand
from numpy import arange

count = ['138','170','155','243','232']
platform =['PlayStation','PlayStation','PlayStation','PC','PlayStation']
def autolabel(rects):
# attach some text labels
    for ii,rect in enumerate(rects):
        width = int(rect.get_width())

        height = rect.get_height()
        print(height,width)
        yloc1=rect.get_y() + height /2.0
        yloc2=rect.get_y() + height /2.0
        if (width <= 5):
            # Shift the text to the right side of the right edge
            xloc1 = width + 1
            yloc2=yloc2+0.3
            # Black against white background
            clr = 'black'
            align = 'left'
        else:
            # Shift the text to the left side of the right edge
            xloc1 = 0.98*width
            # White on blue
            clr = 'white'
            align = 'right'
        yloc1=rect.get_y() + height /2.0
        print(xloc1,yloc1,yloc2)
        ax.text(xloc1,yloc1, '%s'% (count[ii]),horizontalalignment=align,
                         verticalalignment='center',color=clr,weight='bold',
                         clip_on=True)
        ax.text(5,yloc2, '%s'% (platform[ii]),horizontalalignment='left',
                         verticalalignment='center',color=clr,weight='bold',
                         clip_on=True)


val = [138,170,155,243,232]
print(val)# the bar lengths or count in your case
pos = [ 1996 , 1997,  1998,  1999,  2000]    # the bar centers on the y axis
print(pos)

fig = plt.figure()
ax = fig.add_subplot(111)
rects = ax.barh(pos,val, align='center',height=0.4)
print(rects)
autolabel(rects)
ax.set_ylabel('Year')
ax.set_xlabel('Count')
ax.set_title('horizontal bar chart')
ax.grid(False)
plt.savefig("horizontal.png")
plt.show()

Here is the output

这是输出

The part where you will be interestedin very much:

你会非常感兴趣的部分:

def autolabel(rects):
    # attach some text labels
        for ii,rect in enumerate(rects):

            width =  rect.get_width()

            height = rect.get_height()

            yloc1=rect.get_y() + height /2.0
            yloc2=rect.get_y() + height /2.0
            if (width <= 5):
                # Shift the text to the right side of the right edge
                xloc1 = width + 1
                yloc2=yloc2+0.3
                # Black against white background
                clr = 'black'
                align = 'left'
            else:
                # Shift the text to the left side of the right edge
                xloc1 = 0.98*width
                # White on blue
                clr = 'white'
                align = 'right'
            yloc1=rect.get_y() + height /2.0

            ax.text(xloc1,yloc1, '%s'% (count[ii]),horizontalalignment=align,
                             verticalalignment='center',color=clr,weight='bold',
                             clip_on=True)
            ax.text(5,yloc2, '%s'% (platform[ii]),horizontalalignment='left',
                             verticalalignment='center',color=clr,weight='bold',
                             clip_on=True)

1) iivariable comes from enumerate having values 0 to 5. Used to iterate over our lists countand platform

1) ii变量来自枚举值 0 到 5。用于迭代我们的列表countplatform

2) Why an if/else statement in the function? That is for conditions where the width is too little. Say if the first width obtained from val = [138,170,155,243,232]is reduced to 5 i.e val = [5,170,155,243,232]in this case the output would be.

2) 为什么在函数中有一个 if/else 语句?那是针对宽度太小的情况。假设从 获得的第一个宽度val = [138,170,155,243,232]减少到 5,即val = [5,170,155,243,232]在这种情况下输出将是。

This

这个

What we are basically doing is giving xloc (x-coordinate) and yloc (y-coordinate) values for both ax.text()functions.

我们基本上要做的是为这两个ax.text()函数提供 xloc(x 坐标)和 yloc(y 坐标)值。

ax.text(xloc1,yloc1, '%s'% (count[ii]),horizontalalignment=align,
                         verticalalignment='center',color=clr,weight='bold',
                         clip_on=True)
        ax.text(5,yloc2, '%s'% (platform[ii]),horizontalalignment='left',
                         verticalalignment='center',color=clr,weight='bold',
                         clip_on=True)

Function parameters

text(x, y, s, fontdict=None, withdash=False, **kwargs)

x, y : data coordinates

s : string while the other two are optional.

功能参数

文本(x,y,s,fontdict=None,withdash=False,**kwargs)

x, y : 数据坐标

s : 字符串,而其他两个是可选的。

If width is < 5. Then increase yloc a bit. So that text is little bit higher. While change xloc acccordingly.Also changing the color to black. Or else color will be white.

如果宽度 < 5。然后稍微增加 yloc。所以那个文本要高一点。相应地更改 xloc。同时将颜色更改为黑色。否则颜色会是白色的。

It would be bestif you change those values and see how the output changes to gain a better understanding of it.

如果您更改这些值并查看输出如何变化以更好地理解它,那将是最好的

UPDATE:If you don't want the axis to be shown in the output just as in the image you attached you can simple do that typing in ax.axis("off")enter image description here

更新:如果您不希望轴显示在输出中,就像您附加的图像一样,您可以简单地输入ax.axis("off")在此处输入图片说明