I posted a question previously but my wording got it flagged as a duplicate, so I'll be super specific on this one.
This is 13 rows of data, but my df has about 160:
Animal Score
0 Dog 1
1 Pig 2
2 Chicken 3
3 Cat 4
4 Fox 5
5 Whale 6
7 Beetle 7
8 Ox 8
9 Monkey 9
10 Cow 10
11 Duck 11
12 Hen 12
13 Crow 13
I'm trying to annotate a graph with the values, and there is one line of code that's buggin' out on me and I cannot figure out why - ax.set_xticklabels(x_labels)
I think it's because of the concat that's forcing 11 rows instead of the full 160 odd, but here's the code:
#Add custom entries here
custom_df = dfAnimalRankings.loc[dfAnimalRankings['Animals'].isin(['Beetle'])]
# Create new df to show top 5, bottom 5, and Beetle
new_df = pd.concat([dfAnimalRankings[:5], dfAnimalRankings[-5:], custom_df])
new_df.sort_values(by=['Score'], inplace= True)
new_df.reset_index(drop=True, inplace= True)
# Plot the figure.
plt.figure(figsize=(12, 8))
ax = new_df.plot(kind='bar')
ax.set_title('Animal Rankings')
ax.set_xlabel('Animals')
ax.set_ylabel('Score')
ax.set_xticklabels(x_labels)
rects = ax.patches
def add_value_labels(ax, spacing=5):
"""Add labels to the end of each bar in a bar chart.
Arguments:
ax (matplotlib.axes.Axes): The matplotlib object containing the axes
of the plot to annotate.
spacing (int): The distance between the labels and the bars.
"""
# For each bar: Place a label
for rect in ax.patches:
# Get X and Y placement of label from rect.
y_value = rect.get_height()
x_value = rect.get_x() + rect.get_width() / 2
# Number of points between bar and label. Change to your liking.
space = spacing
# Vertical alignment for positive values
va = 'bottom'
# If value of bar is negative: Place label below bar
if y_value < 0:
# Invert space to place label below
space *= -1
# Vertically align label at top
va = 'top'
# Use Y value as label and format number with one decimal place
label = "{:.1f}".format(y_value)
# Create annotation
ax.annotate(
label, # Use `label` as label
(x_value, y_value), # Place label at end of the bar
xytext=(0, space), # Vertically shift label by `space`
textcoords="offset points", # Interpret `xytext` as offset in points
ha='center', # Horizontally center label
va=va) # Vertically align label differently for
# positive and negative values.
# Call the function above. All the magic happens there.
add_value_labels(ax)
plt.savefig("image.png")
If I run the above code, I get the following error:
The number of FixedLocator locations (11), usually from a call to set_ticks, does not match the number of ticklabels (166).
But if I run this code:
#Add custom entries here
custom_df = dfAnimalRankings.loc[dfAnimalRankings['Animals'].isin(['Beetle'])]
# Create new df to show top 5, bottom 5, and Beetle
new_df = pd.concat([dfAnimalRankings[:5], dfAnimalRankings[-5:], custom_df])
new_df.sort_values(by=['Score'], inplace= True)
new_df.reset_index(drop=True, inplace= True)
# Plot the figure.
plt.figure(figsize=(12, 8))
ax = new_df.plot(kind='bar')
ax.set_title('Animal Rankings')
ax.set_xlabel('Animals')
ax.set_ylabel('Score')
# ax.set_xticklabels(x_labels)
rects = ax.patches
def add_value_labels(ax, spacing=5):
"""Add labels to the end of each bar in a bar chart.
Arguments:
ax (matplotlib.axes.Axes): The matplotlib object containing the axes
of the plot to annotate.
spacing (int): The distance between the labels and the bars.
"""
# For each bar: Place a label
for rect in ax.patches:
# Get X and Y placement of label from rect.
y_value = rect.get_height()
x_value = rect.get_x() + rect.get_width() / 2
# Number of points between bar and label. Change to your liking.
space = spacing
# Vertical alignment for positive values
va = 'bottom'
# If value of bar is negative: Place label below bar
if y_value < 0:
# Invert space to place label below
space *= -1
# Vertically align label at top
va = 'top'
# Use Y value as label and format number with one decimal place
label = "{:.1f}".format(y_value)
# Create annotation
ax.annotate(
label, # Use `label` as label
(x_value, y_value), # Place label at end of the bar
xytext=(0, space), # Vertically shift label by `space`
textcoords="offset points", # Interpret `xytext` as offset in points
ha='center', # Horizontally center label
va=va) # Vertically align label differently for
# positive and negative values.
# Call the function above. All the magic happens there.
add_value_labels(ax)
plt.savefig("image.png")
I get this (I'm aware the numbers don't match, but it's an output from my actual dataset not the sample above):
Why does that one line of code break the annotation? And how can I get the data labels, which are animal names and not the numbers, added to the chart?
Cheers