Menambahkan label nilai pada diagram batang matplotlib


95

Saya terjebak pada sesuatu yang rasanya relatif mudah. Kode yang saya bawa di bawah ini adalah contoh berdasarkan proyek yang lebih besar yang sedang saya kerjakan. Saya tidak melihat alasan untuk memposting semua detail, jadi terimalah struktur data yang saya bawa apa adanya.

Pada dasarnya, saya membuat diagram batang, dan saya hanya bisa mengetahui cara menambahkan label nilai pada batang (di tengah batang, atau tepat di atasnya). Telah melihat sampel di seluruh web tetapi tidak berhasil menerapkan kode saya sendiri. Saya percaya solusinya adalah dengan 'teks' atau 'anotasi', tetapi saya: a) tidak tahu mana yang akan digunakan (dan secara umum, belum tahu kapan harus menggunakan yang mana). b) tidak dapat melihat untuk menyajikan label nilai. Sangat menghargai bantuan Anda, kode saya di bawah ini. Terima kasih sebelumnya!

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)

Jawaban:


120

Pertama freq_series.plotmengembalikan sumbu bukan gambar jadi untuk membuat jawaban saya sedikit lebih jelas, saya telah mengubah kode yang Anda berikan untuk merujuknya axdaripada figlebih konsisten dengan contoh kode lainnya.

Anda bisa mendapatkan daftar batang yang diproduksi di plot dari ax.patchesanggota. Kemudian Anda dapat menggunakan teknik yang ditunjukkan dalam contoh galeri inimatplotlib untuk menambahkan label menggunakan ax.textmetode tersebut.

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

Ini menghasilkan plot berlabel yang terlihat seperti:

masukkan deskripsi gambar di sini


Hai Simon! Pertama, terima kasih banyak telah menjawab! Kedua, saya rasa saya tidak jelas - saya ingin menunjukkan nilai y. Saya baru saja mengganti label di zip (,) dengan frekuensi. Sekarang, bisakah Anda menjelaskan lebih lanjut tentang kapak ara Vs? Membuat saya bingung. Frasa / sumber pencarian yang baik juga akan bagus, karena sedikit umum untuk pencarian Google. Sangat dihargai!
Optimesh

Sosok adalah kumpulan dari satu atau lebih sumbu, misalnya dalam contoh ini matplotlib.org/examples/statistics/… ini adalah satu gambar yang terdiri dari 4 sumbu berbeda.
Simon Gibbons

Terima kasih lagi. Bisakah Anda membantu saya memahami perbedaan antara anotasi dan teks? Terima kasih!
Optimesh

2
Keduanya dapat digunakan untuk menambahkan teks ke plot. texthanya mencetak beberapa teks ke plot, sementara annotatemerupakan helper yang dapat Anda gunakan untuk dengan mudah juga menambahkan panah dari teks yang menunjuk ke titik tertentu pada plot yang dirujuk oleh teks.
Simon Gibbons

10
Solusi bagus. Saya menulis posting blog yang didasarkan pada solusi di sini dan memberikan versi yang sedikit lebih kuat yang berskala sesuai dengan tinggi sumbu, jadi kode yang sama berfungsi untuk plot berbeda yang memiliki ketinggian sumbu berbeda: komposisi.al/blog/2015/ 11/29 /…
Lindsey Kuper

66

Berdasarkan fitur yang disebutkan dalam jawaban untuk pertanyaan lain ini, saya telah menemukan solusi yang dapat diterapkan secara umum untuk menempatkan label pada diagram batang.

Sayangnya, solusi lain tidak berfungsi dalam banyak kasus, karena jarak antara label dan batang ditentukan dalam satuan absolut batang atau diskalakan dengan ketinggian batang . Yang pertama hanya berfungsi untuk rentang nilai yang sempit dan yang terakhir memberikan jarak yang tidak konsisten dalam satu plot. Tidak ada yang bekerja dengan baik dengan sumbu logaritmik.

Solusi yang saya usulkan bekerja secara independen dari skala (yaitu untuk bilangan kecil dan besar) dan bahkan menempatkan label dengan benar untuk nilai negatif dan dengan skala logaritmik karena menggunakan unit visual pointsuntuk offset.

Saya telah menambahkan angka negatif untuk menunjukkan penempatan label yang benar dalam kasus seperti itu.

Nilai ketinggian setiap batang digunakan sebagai label untuk itu. Label lain dapat dengan mudah digunakan dengan potongan Simonfor rect, label in zip(rects, labels) .

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")

Sunting: Saya telah mengekstrak fungsionalitas yang relevan dalam suatu fungsi, seperti yang disarankan oleh barnhillec .

Ini menghasilkan keluaran sebagai berikut:

Bagan batang dengan label yang ditempatkan secara otomatis di setiap batang

Dan dengan skala logaritmik (dan beberapa penyesuaian pada data masukan untuk menampilkan penskalaan logaritmik), inilah hasilnya:

Bagan batang dengan skala logaritmik dengan label yang ditempatkan secara otomatis di setiap batang


1
Jawaban yang fantastis! Terima kasih. Ini bekerja dengan sempurna dengan panda dalam pembuatan plot batang.
m4p85r

1
Perbaikan yang disarankan: gunakan ax.annotate daripada plt.annotate. Perubahan ini akan memungkinkan seluruh rutinitas untuk dienkapsulasi dalam fungsi yang melewati sumbu sumbu, yang kemudian dapat difaktorkan ke dalam fungsi utilitas plot mandiri yang berguna.
barnhillec

@barnhillec, terima kasih atas sarannya. Saya telah melakukan itu di suntingan saya. Perhatikan, bahwa saat ini ini hanya berfungsi dengan bagan batang vertikal dan tidak dengan jenis plot lain (mungkin dengan histogram). Menjadikan fungsi lebih umum juga akan membuatnya lebih sulit untuk dipahami dan karenanya kurang cocok untuk jawaban di sini.
justfortherec

Jawaban yang sangat kuat daripada jawaban lain yang saya temukan. Jelaskan dengan baik setiap baris dengan komentar membantu saya mengasimilasi seluruh gagasan.
code_conundrum

35

Berdasarkan jawaban di atas (hebat!), Kita juga dapat membuat plot batang horizontal hanya dengan beberapa penyesuaian:

# 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")

plot batang horizontal dengan anotasi


1
Untuk kisi yang ditampilkan:freq_series.plot(kind='barh', grid=True)
penginapan

Bekerja sempurna bahkan dengan diagram batang Grup. Terima kasih.
Prabah

Selesai dengan baik dengan grafik batang horizontal!
code_conundrum

Bagi saya, angka tersebut berpotongan dengan kotak yang mengelilingi diagram batang. Apakah ada cara untuk mencegah hal ini?
bweber13

ax.set_xlim([0, 1.1*max_value])
Memecahkan

14

Jika Anda hanya ingin memberi label titik data di atas bilah, Anda bisa menggunakan plt.annotate ()

Kode saya:

import numpy as np
import matplotlib.pyplot as plt

n = [1,2,3,4,5,]
s = [i**2 for i in n]
line = plt.bar(n,s)
plt.xlabel('Number')
plt.ylabel("Square")

for i in range(len(s)):
    plt.annotate(str(s[i]), xy=(n[i],s[i]), ha='center', va='bottom')

plt.show()

Dengan menentukan perataan horizontal dan vertikal 'center'dan 'bottom'masing - masing dapat memperoleh anotasi di tengah.

diagram batang berlabel


1
bersih dan sederhana
Ethan Yanjia Li

Dapatkah Anda menambahkan bagaimana kami dapat menempatkan label tepat di tengah?
x89

@ x89 Anda dapat menentukan perataan horizontal dan vertikal dari teks yang melakukan pemusatan. - Saya telah mengedit jawaban untuk memperbaikinya dengan itu.
Simon Gibbons

0

Jika Anda hanya ingin menambahkan Titik Data di atas bilah, Anda dapat dengan mudah melakukannya dengan:

 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
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.