2015-03-08 22 views
38

Utknąłem na czymś, co powinno być względnie łatwe. Poniższy kod jest próbką opartą na większym projekcie, nad którym pracuję. Nie widziałem powodu, aby publikować wszystkie szczegóły, więc proszę przyjąć struktury danych, które przynoszę.Dodawanie etykiet wartości na wykresie słupkowym matplotlib

Zasadniczo tworzę wykres słupkowy i mogę po prostu dowiedzieć się, jak dodawać etykiety wartości na słupkach (na środku paska lub tuż nad nim). Szukałem próbek w Internecie, ale bezskutecznie wdrażałem własny kod. Uważam, że rozwiązaniem jest albo "tekst", albo "adnotacja", ale ja: a) nie wiem, którego użyć (i ogólnie mówiąc, nie wiem, kiedy go użyć). b) nie widać, aby wyświetlić etykiety wartości. Doceniam twoją pomoc, mój kod poniżej. Z góry dziękuję!

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 ma wersję demo: https://matplotlib.org/examples/api/barchart_demo.html – Dan

Odpowiedz

63

pierwsze freq_series.plot zwraca oś nie postać tak, aby moja odpowiedź trochę bardziej jasne Zmieniłem swój kod podany na odwoływanie się do niego jako ax zamiast fig być bardziej spójne z innymi przykładami kodu .

Możesz otrzymać listę słupków wyprodukowanych na działce od członka ax.patches. Następnie możesz użyć techniki pokazanej w this matplotlib gallery example, aby dodać etykiety przy użyciu metody 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") 

To daje oznaczony wykres, który wygląda tak:

enter image description here

+0

Hi Si mon!Po pierwsze, bardzo dziękuję za odpowiedź! Po drugie, wydaje mi się, że byłem niejasny - chciałem pokazać wartość y. Właśnie zamieniłem etykiety w zip (,) na częstotliwości. A teraz, czy mógłbyś rzucić trochę więcej światła na figi Vs? Mam mnie zdezorientowany. Dobra wyszukiwana fraza/zasób również byłaby świetna, ponieważ jest nieco ogólna dla wyszukiwania goog. Bardzo doceniane! – Optimesh

+0

Rysunek jest zbiorem jednej lub więcej osi, np. w tym przykładzie w tym przykładzie http://matplotlib.org/examples/statistics/histogram_demo_multihist.html jest to jedna postać składająca się z 4 różnych osi. –

+0

Jeszcze raz dziękuję. Czy możesz mi pomóc zrozumieć różnice pomiędzy adnotacjami a tekstem? Dzięki! – Optimesh

5

opiera się na funkcji wymienionej w this answer to another question Znalazłem bardzo ogólnie obowiązujące rozwiązanie dla umieszczania etykiet na wykresie słupkowym.

Inne rozwiązania niestety nie działają w wielu przypadkach, ponieważ odstępy między etykietą i słupkiem wynoszą given in absolute units of the bars lub scaled by the height of the bar. Ten pierwszy działa tylko dla wąskiego zakresu wartości, a drugi daje niespójne odstępy w obrębie jednego wykresu. Żadne z nich nie działa dobrze z osiami logarytmicznymi.

Proponowane przeze mnie rozwiązanie działa niezależnie od skali (np. Dla małych i dużych liczb), a nawet poprawnie umieszcza etykiety dla wartości ujemnych i ze skalami logarytmicznymi, ponieważ wykorzystuje do wyświetlania przesunięć jednostkę wizualną points.

Dodałem ujemną liczbę, aby zaprezentować prawidłowe umieszczenie etykiet w takim przypadku.

Wartość wysokości każdego słupka jest używana jako etykieta. Inne etykiety można z łatwością używać z 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") 

To daje następujący wynik:

Bar chart with automatically placed labels on each bar

I ze skali logarytmicznej (i niektóre korekty do danych wejściowych do zaprezentowania skalowanie logarytmicznej), jest to wynikiem:

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

+1

Fantastyczna odpowiedź! Dzięki. To działało bezbłędnie z pandami w budowanym spisku barowym. – ashgetstazered

Powiązane problemy