Je me suis retrouvé coincé sur quelque chose qui devrait être relativement facile. Le code que j'apporte ci-dessous est un exemple basé sur un projet plus vaste sur lequel je travaille. Je ne voyais aucune raison d'afficher tous les détails, acceptez donc les structures de données que j'apporte en l'état.
Fondamentalement, je crée un graphique à barres et je peux juste comprendre comment ajouter des étiquettes de valeur sur les barres (au centre de la barre ou juste au-dessus). Je cherche des exemples sur le Web, mais sans succès avec mon propre code. Je crois que la solution est soit avec 'text' soit 'annotate', mais je: a) ne sais pas lequel utiliser (et d'une manière générale, je n'ai pas compris quand utiliser lequel). b) ne peut pas voir non plus présenter les étiquettes de valeur. J'apprécierais votre aide, mon code ci-dessous. Merci d'avance!
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
pd.set_option('display.mpl_style', 'default')
%matplotlib inline
# 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))
fig = freq_series.plot(kind='bar')
fig.set_title('Amount Frequency')
fig.set_xlabel('Amount ($)')
fig.set_ylabel('Frequency')
fig.set_xticklabels(x_labels)
Tout d'abord _freq_series.plot
_ renvoie un axe et non un chiffre afin de clarifier ma réponse, j'ai changé votre code pour y faire référence comme ax
plutôt que fig
pour être plus cohérent avec d'autres exemples de code.
Vous pouvez obtenir la liste des barres produites dans le graphique à partir du membre _ax.patches
_. Vous pouvez ensuite utiliser la technique présentée dans cet exemple de galerie matplotlib
pour ajouter les étiquettes à l'aide de la méthode ax.text
.
_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)
rects = ax.patches
# Make some labels.
labels = ["label%d" % i for i in xrange(len(rects))]
for rect, label in Zip(rects, labels):
height = rect.get_height()
ax.text(rect.get_x() + rect.get_width() / 2, height + 5, label,
ha='center', va='bottom')
_
Cela produit un graphique étiqueté qui ressemble à:
Basé sur une fonctionnalité mentionnée dans cette réponse à une autre question , j'ai trouvé une solution très générale pour placer des étiquettes sur un graphique à barres.
D’autres solutions ne fonctionnent malheureusement pas dans de nombreux cas, car l’espacement entre étiquette et barre est soit donné en unités absolues des barres ou est mis à l’échelle par la hauteur de la barre . Le premier ne fonctionne que pour une plage de valeurs étroite et le dernier donne un espacement incohérent dans une parcelle. Aucun des deux ne fonctionne bien avec les axes logarithmiques.
La solution que je propose fonctionne indépendamment de l’échelle (c’est-à-dire pour les petits et les grands nombres) et place même correctement les étiquettes pour les valeurs négatives et avec les échelles logarithmiques, car elle utilise l’unité visuelle points
pour les décalages.
J'ai ajouté un nombre négatif pour montrer le bon placement des étiquettes dans un tel cas.
La valeur de la hauteur de chaque barre sert d’étiquette. D'autres étiquettes peuvent facilement être utilisées avec extrait de for rect, label in Zip(rects, labels)
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 les fonctionnalités pertinentes d'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 mettre en valeur la mise à l'échelle logarithmique), voici le résultat:
En nous appuyant sur la réponse ci-dessus (très bien!), Nous pouvons également créer un tracé graphique en barres horizontales avec juste quelques ajustements:
# Bring some raw data.
frequencies = [6, -16, 75, 160, 244, 260, 145, 73, 16, 4, 1]
freq_series = pd.Series(frequencies)
y_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='barh')
ax.set_title('Amount Frequency')
ax.set_xlabel('Frequency')
ax.set_ylabel('Amount ($)')
ax.set_yticklabels(y_labels)
ax.set_xlim(-40, 300) # expand xlim to make labels easier to read
rects = ax.patches
# For each bar: Place a label
for rect in rects:
# Get X and Y placement of label from rect.
x_value = rect.get_width()
y_value = rect.get_y() + rect.get_height() / 2
# Number of points between bar and label. Change to your liking.
space = 5
# Vertical alignment for positive values
ha = 'left'
# If value of bar is negative: Place label left of bar
if x_value < 0:
# Invert space to place label to the left
space *= -1
# Horizontally align label at right
ha = 'right'
# Use X value as label and format number with one decimal place
label = "{:.1f}".format(x_value)
# Create annotation
plt.annotate(
label, # Use `label` as label
(x_value, y_value), # Place label at end of the bar
xytext=(space, 0), # Horizontally shift label by `space`
textcoords="offset points", # Interpret `xytext` as offset in points
va='center', # Vertically center label
ha=ha) # Horizontally align label differently for
# positive and negative values.
plt.savefig("image.png")
Si vous souhaitez uniquement ajouter des points de données au-dessus des barres, vous pouvez facilement le faire avec:
for i in range(len(frequencies)): # your number of bars
plt.text(x = x_values[i]-0.25, #takes your x values as horizontal positioning argument
y = y_values[i]+1, #takes your y values as vertical positioning argument
s = data_labels[i], # the labels you want to add to the data
size = 9) # font size of datalabels