Sur la base d'une fonctionnalité mentionnée dans cette réponse à une autre question, j'ai trouvé une solution très généralement applicable pour placer des étiquettes sur un graphique à barres.
D'autres solutions ne fonctionnent malheureusement pas dans de nombreux cas, car l'espacement entre l'étiquette et la barre est soit donné en unités absolues des barres, soit mis à l'échelle par la hauteur de la barre . Le premier ne fonctionne que pour une plage étroite de valeurs et le second donne un espacement incohérent dans un graphique. Ni l'un ni l'autre ne fonctionne bien avec les axes logarithmiques.
La solution que je propose fonctionne indépendamment de l'échelle (ie pour les petits et grands nombres) et place même correctement les étiquettes pour les valeurs négatives et avec des échelles logarithmiques car elle utilise l'unité visuelle points
pour les décalages.
J'ai ajouté un nombre négatif pour montrer le placement correct des étiquettes dans un tel cas.
La valeur de la hauteur de chaque barre est utilisée comme étiquette pour celle-ci. D'autres étiquettes peuvent facilement être utilisées avec l' for rect, label in zip(rects, labels)
extrait de Simon .
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# Bring some raw data.
frequencies = [6, -16, 75, 160, 244, 260, 145, 73, 16, 4, 1]
# In my original code I create a series and run on that,
# so for consistency I create a series from the list.
freq_series = pd.Series.from_array(frequencies)
x_labels = [108300.0, 110540.0, 112780.0, 115020.0, 117260.0, 119500.0,
121740.0, 123980.0, 126220.0, 128460.0, 130700.0]
# Plot the figure.
plt.figure(figsize=(12, 8))
ax = freq_series.plot(kind='bar')
ax.set_title('Amount Frequency')
ax.set_xlabel('Amount ($)')
ax.set_ylabel('Frequency')
ax.set_xticklabels(x_labels)
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")
Edit: J'ai extrait la fonctionnalité pertinente dans une fonction, comme suggéré par barnhillec .
Cela produit la sortie suivante:
Et avec l'échelle logarithmique (et quelques ajustements aux données d'entrée pour présenter la mise à l'échelle logarithmique), voici le résultat: