user517696
user517696

Reputation: 2672

How to show values inside the bars of a bargraph?

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?

Upvotes: 5

Views: 11720

Answers (2)

void
void

Reputation: 2642

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

Here is the output

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.

This

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")enter image description here

Upvotes: 3

David Jaimes
David Jaimes

Reputation: 341

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

enter image description here

Upvotes: 16

Related Questions