How to show values inside the bars of a bargraph?

前端 未结 2 883
星月不相逢
星月不相逢 2021-01-06 10:01

I have a dataframe like this:

                 platform     count
release_year        
         1996    PlayStation   138
         1997    PlayStation   170
         


        
相关标签:
2条回答
  • 2021-01-06 10:34

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

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

    0 讨论(0)
  • 2021-01-06 10:41

    Not sure if you want it to be in Percentage % or as count number itself. 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

    Dataframe to list 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 labels inside 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()
    

    The part where you will be interested in 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) ii variable comes from enumerate having values 0 to 5. Used to iterate over our lists count and platform

    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.

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

    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.

    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.

    It would be best if 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")

    0 讨论(0)
提交回复
热议问题