1

I try to produce a plot and want to automatically add text (in this case is percentage) to each circle in correspond to each y axis types. Any help would be very helpful.

# import libraries
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline
# Make some data
index=['Stream flow',
 'Soil moisture',
 'Water indices',
 'Others',
 'Temperature',
 'Precipitation',
 'Vegetative indices']
value=[2.13, 6.38, 10.64, 12.77, 17.73, 21.99, 28.37]

# create dataframe
percentages = pd.Series(value,index=index)
df = pd.DataFrame({'percentage' : percentages})
df = df.sort_values(by='percentage')

# we first need a numeric placeholder for the y axis
my_range=list(range(1,len(df.index)+1))

fig, ax = plt.subplots(figsize=(15,8))

# create for each expense type an horizontal line that starts at x = 0 with the length 
plt.hlines(y=my_range, xmin=0, xmax=df['percentage']-0.5, color='black', alpha=0.8, linewidth=1)

# create for each expense type a dot at the level of the expense percentage value
line=plt.plot(df['percentage'], my_range, "o", markersize=30, color='#fd8c00', alpha=0.6, linewidth=0.3)

# set labels
ax.set_xlabel('Percentage', fontsize=15)
ax.set_ylabel('')

# set axis
ax.tick_params(axis='both', which='major', labelsize=14)
plt.yticks(my_range, df.index)


ax.set_xlim(0,30)

1 Answer 1

1

You can use matplotlib.axes.Axes.text:

x_space = 0.4
y_space = 0.05
fontsize = 7
for y_i, val in enumerate(value, 1):
    ax.text(x = val - x_space, y = y_i - y_space, s = f'{val}%', fontsize = fontsize)

You have to adjust x_space, y_space and fontsize in order to fit properly the text within the circles.

Complete code

# import libraries
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline
# Make some data
index=['Stream flow',
 'Soil moisture',
 'Water indices',
 'Others',
 'Temperature',
 'Precipitation',
 'Vegetative indices']
value=[2.13, 6.38, 10.64, 12.77, 17.73, 21.99, 28.37]

# create dataframe
percentages = pd.Series(value,index=index)
df = pd.DataFrame({'percentage' : percentages})
df = df.sort_values(by='percentage')

# we first need a numeric placeholder for the y axis
my_range=list(range(1,len(df.index)+1))

fig, ax = plt.subplots(figsize=(15,8))

# create for each expense type an horizontal line that starts at x = 0 with the length 
plt.hlines(y=my_range, xmin=0, xmax=df['percentage']-0.5, color='black', alpha=0.8, linewidth=1)

# create for each expense type a dot at the level of the expense percentage value
line=plt.plot(df['percentage'], my_range, "o", markersize=30, color='#fd8c00', alpha=0.6, linewidth=0.3)

# set labels
ax.set_xlabel('Percentage', fontsize=15)
ax.set_ylabel('')

# set axis
ax.tick_params(axis='both', which='major', labelsize=14)
plt.yticks(my_range, df.index)

ax.set_xlim(0,30)


x_space = 0.4
y_space = 0.05
for y_i, val in enumerate(value, 1):
    ax.text(x = val - x_space, y = y_i - y_space, s = f'{val:>5.2f}%', fontsize = 7)


plt.show()

enter image description here


Same code as above, but with increased circle radius and font, in order to improve readability.

# import libraries
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline
# Make some data
index=['Stream flow',
 'Soil moisture',
 'Water indices',
 'Others',
 'Temperature',
 'Precipitation',
 'Vegetative indices']
value=[2.13, 6.38, 10.64, 12.77, 17.73, 21.99, 28.37]

# create dataframe
percentages = pd.Series(value,index=index)
df = pd.DataFrame({'percentage' : percentages})
df = df.sort_values(by='percentage')

# we first need a numeric placeholder for the y axis
my_range=list(range(1,len(df.index)+1))

fig, ax = plt.subplots(figsize=(15,8))

# create for each expense type an horizontal line that starts at x = 0 with the length 
plt.hlines(y=my_range, xmin=0, xmax=df['percentage']-0.85, color='black', alpha=0.8, linewidth=1)

# create for each expense type a dot at the level of the expense percentage value
line=plt.plot(df['percentage'], my_range, "o", markersize=50, color='#fd8c00', alpha=0.6, linewidth=0.3)

# set labels
ax.set_xlabel('Percentage', fontsize=15)
ax.set_ylabel('')

# set axis
ax.tick_params(axis='both', which='major', labelsize=14)
plt.yticks(my_range, df.index)

ax.set_xlim(0,30)
ax.set_ylim(0, len(value) + 1)

x_space = 0.75
y_space = 0.06
fontsize = 12
for y_i, val in enumerate(value, 1):
    ax.text(x = val - x_space, y = y_i - y_space, s = f'{val:>5.2f}%', fontsize = fontsize)


plt.show()

enter image description here


Even better, you can use matplotlib.axes.Axes.annotate to get rid of x_space and y_space:

fontsize = 12
for y_i, x_i in enumerate(value, 1):
    ax.annotate(f'{x_i:>5.2f}%', xy = (x_i, y_i), xytext = (0, 0), textcoords = 'offset points', ha = 'center', va = 'center', fontsize = fontsize)

You still have to adjust the fontsize to properly fit the radius of the circles.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.