2015-03-08 6 views
38

Mi sono bloccato su qualcosa che dovrebbe essere relativamente facile. Il codice che porto qui sotto è un esempio basato su un progetto più ampio su cui sto lavorando. Non ho visto alcun motivo per pubblicare tutti i dettagli, quindi per favore accetta le strutture dati che porto come sono.Aggiunta di etichette di valore su un grafico a barre matplotlib

Fondamentalmente, sto creando un grafico a barre, e posso solo capire come aggiungere etichette di valore sulle barre (al centro della barra o appena sopra). Ho guardato i campioni sul web ma senza successo implementando sul mio codice. Credo che la soluzione sia con 'testo' o 'annotazione', ma io: a) non so quale usare (e in generale, non ho capito quando usare quale). b) non può vedere per ottenere o per presentare le etichette dei valori. Gradirei il tuo aiuto, il mio codice qui sotto. Grazie in anticipo!

import numpy as np 
import pandas as pd 
import matplotlib.pyplot as plt 
pd.set_option('display.mpl_style', 'default') 
%matplotlib inline 


frequencies = [6, 16, 75, 160, 244, 260, 145, 73, 16, 4, 1] # bring some raw data 

freq_series = pd.Series.from_array(frequencies) # in my original code I create a series and run on that, so for consistency I create a series from the list. 

x_labels = [108300.0, 110540.0, 112780.0, 115020.0, 117260.0, 119500.0, 121740.0, 123980.0, 126220.0, 128460.0, 130700.0] 

# now to 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) 
+1

Matplotlib ha una demo: https://matplotlib.org/examples/api/barchart_demo.html – Dan

risposta

63

In primo luogo freq_series.plot restituisce un asse non una figura in modo da rendere la mia risposta un po 'più chiaro ho cambiato il codice dato a riferirsi ad esso come ax piuttosto che fig ad essere più coerente con altri esempi di codice .

È possibile ottenere l'elenco delle barre prodotte nella trama dal membro ax.patches. Quindi è possibile utilizzare la tecnica dimostrata in this matplotlib gallery example per aggiungere le etichette utilizzando il metodo ax.text.

import numpy as np 
import pandas as pd 
import matplotlib.pyplot as plt 

frequencies = [6, 16, 75, 160, 244, 260, 145, 73, 16, 4, 1] # bring some raw data 

freq_series = pd.Series.from_array(frequencies) # in my original code I create a series and run on that, so for consistency I create a series from the list. 

x_labels = [108300.0, 110540.0, 112780.0, 115020.0, 117260.0, 119500.0, 121740.0, 123980.0, 126220.0, 128460.0, 130700.0] 

# now to 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 

# Now 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') 

plt.savefig("image.png") 

Questo produce una trama etichetta che assomiglia:

enter image description here

+0

Ciao Si mon!Innanzitutto, grazie mille per aver risposto! Secondo, immagino di non essere chiaro: volevo mostrare il valore y. Ho appena sostituito le etichette nello zip (,) con le frequenze. Ora, potresti per favore versare un po 'più di luce sull'ascia di fico? Mi ha confuso Una buona frase/risorsa di ricerca sarebbe anche ottima, dato che è un po 'generica per una ricerca goog. Molto apprezzato! – Optimesh

+0

Una figura è una raccolta di uno o più assi, ad es. in questo esempio http://matplotlib.org/examples/statistics/histogram_demo_multihist.html è una figura composta da 4 diversi assi. –

+0

Grazie ancora. Potete per favore aiutarmi a capire diff tra annotate e testo? Grazie! – Optimesh

5

Sulla base di una caratteristica di cui this answer to another question ho trovato una soluzione molto generalmente applicabile per l'immissione etichette su un grafico a barre.

Altre soluzioni purtroppo non funzionano in molti casi, perché la spaziatura tra etichetta e barra è given in absolute units of the bars o è scaled by the height of the bar. Il primo funziona solo per un intervallo ristretto di valori e il secondo fornisce una spaziatura incoerente all'interno di un grafico. Né funziona bene con gli assi logaritmici.

La soluzione che propongo funziona indipendentemente dalla scala (vale a dire per numeri piccoli e grandi) e posiziona anche correttamente le etichette per valori negativi e con scale logaritmiche perché utilizza l'unità di visualizzazione points per gli offset.

Ho aggiunto un numero negativo per mostrare il corretto posizionamento delle etichette in tal caso.

Il valore dell'altezza di ogni barra viene utilizzato come etichetta per esso. Altre etichette possono essere facilmente utilizzate con Simon's for rect, label in zip(rects, labels) snippet.

import numpy as np 
import pandas as pd 
import matplotlib.pyplot as plt 

frequencies = [6, -16, 75, 160, 244, 260, 145, 73, 16, 4, 1] # bring some raw data 

freq_series = pd.Series.from_array(frequencies) # in my original code I create a series and run on that, so for consistency I create a series from the list. 

x_labels = [108300.0, 110540.0, 112780.0, 115020.0, 117260.0, 119500.0, 121740.0, 123980.0, 126220.0, 128460.0, 130700.0] 

# now to 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 

# For each bar: Place a label 
for rect in rects: 
    # 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 = 5 
    # 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 
    plt.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. 

plt.savefig("image.png") 

Questo produce il seguente output:

Bar chart with automatically placed labels on each bar

E con scala logaritmica (e qualche aggiustamento ai dati di ingresso per mostrare scala logaritmica), questo è il risultato:

Bar chart with logarithmic scale with automatically placed labels on each bar

+1

Risposta fantastica! Grazie. Questo ha funzionato perfettamente con i panda nella trama del bar costruito. – ashgetstazered