I have a dataframe like this:
platform count
release_year
1996 PlayStation 138
1997 PlayStation 170
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")
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")