Làm thế nào để hiển thị giá trị của thanh trên mỗi thanh với pyplot.barh ()?


105

Tôi đã tạo một biểu đồ thanh, làm cách nào để hiển thị giá trị của thanh trên mỗi thanh?

Cốt truyện hiện tại:

nhập mô tả hình ảnh ở đây

Những gì tôi đang cố gắng đạt được:

nhập mô tả hình ảnh ở đây

Mã của tôi:

import os
import numpy as np
import matplotlib.pyplot as plt

x = [u'INFO', u'CUISINE', u'TYPE_OF_PLACE', u'DRINK', u'PLACE', u'MEAL_TIME', u'DISH', u'NEIGHBOURHOOD']
y = [160, 167, 137, 18, 120, 36, 155, 130]

fig, ax = plt.subplots()    
width = 0.75 # the width of the bars 
ind = np.arange(len(y))  # the x locations for the groups
ax.barh(ind, y, width, color="blue")
ax.set_yticks(ind+width/2)
ax.set_yticklabels(x, minor=False)
plt.title('title')
plt.xlabel('x')
plt.ylabel('y')      
#plt.show()
plt.savefig(os.path.join('test.png'), dpi=300, format='png', bbox_inches='tight') # use format='svg' or 'pdf' for vectorial pictures

Câu trả lời:


172

Thêm vào:

for i, v in enumerate(y):
    ax.text(v + 3, i + .25, str(v), color='blue', fontweight='bold')

kết quả:

nhập mô tả hình ảnh ở đây

Các giá trị y vvừa là vị trí x vừa là giá trị chuỗi ax.text, và thuận tiện là barplot có số liệu là 1 cho mỗi thanh, do đó, kiểu liệt kê ilà vị trí y.


11
có lẽ thay thế sử dụng va = 'center', thay vì "i + .25" cho sự liên kết ngang
mathause

11
plt.text(v, i, " "+str(v), color='blue', va='center', fontweight='bold')
João Cartucho

Làm cách nào để chặn kết xuất văn bản trong sổ ghi chép jupyter? ";" ở cuối không hoạt động.
Ralf Hundewadt

Nếu tôi muốn in NEIGHBORHOOD trên đầu thanh và giống nhau cho tất cả các thanh baove, thay vì ở bên trái, thì cần phải làm gì. đã thử và tìm kiếm nhiều nơi nhưng không có manh mối cho đến bây giờ.
Rishi Bansal

@RalfHundewadt chỉ đặt một plt.show()mệnh đề ở cuối. Ví dụ: df.plot(); plt.show()
Jairo Alves

36

Tôi đã nhận thấy mã ví dụ api chứa một ví dụ về mã vạch với giá trị của thanh được hiển thị trên mỗi thanh:

"""
========
Barchart
========

A bar plot with errorbars and height labels on individual bars
"""
import numpy as np
import matplotlib.pyplot as plt

N = 5
men_means = (20, 35, 30, 35, 27)
men_std = (2, 3, 4, 1, 2)

ind = np.arange(N)  # the x locations for the groups
width = 0.35       # the width of the bars

fig, ax = plt.subplots()
rects1 = ax.bar(ind, men_means, width, color='r', yerr=men_std)

women_means = (25, 32, 34, 20, 25)
women_std = (3, 5, 2, 3, 3)
rects2 = ax.bar(ind + width, women_means, width, color='y', yerr=women_std)

# add some text for labels, title and axes ticks
ax.set_ylabel('Scores')
ax.set_title('Scores by group and gender')
ax.set_xticks(ind + width / 2)
ax.set_xticklabels(('G1', 'G2', 'G3', 'G4', 'G5'))

ax.legend((rects1[0], rects2[0]), ('Men', 'Women'))


def autolabel(rects):
    """
    Attach a text label above each bar displaying its height
    """
    for rect in rects:
        height = rect.get_height()
        ax.text(rect.get_x() + rect.get_width()/2., 1.05*height,
                '%d' % int(height),
                ha='center', va='bottom')

autolabel(rects1)
autolabel(rects2)

plt.show()

đầu ra:

nhập mô tả hình ảnh ở đây

FYI Đơn vị của biến chiều cao trong "barh" của matplotlib là gì? (hiện tại, không có cách nào dễ dàng để đặt chiều cao cố định cho mỗi thanh)


1
Có vẻ như get_x () làm tròn số ngay cả khi x ban đầu có chữ số thập phân. Làm cách nào để hiển thị nhiều chữ số thập phân hơn?
ru111

1
muộn để đảng nhưng đối với bất cứ ai khác sử dụng này sử dụng chiều cao + 0.1 thay vì 1,05 * chiều cao trong hàm autolabel tạo ra một khoảng cách phù hợp giữa thanh và văn bản
jnPy

19

Đối với bất kỳ ai muốn có nhãn của họ ở cuối các thanh của họ, chỉ cần chia v cho giá trị của nhãn như sau:

for i, v in enumerate(labels):
    axes.text(i-.25, 
              v/labels[i]+100, 
              labels[i], 
              fontsize=18, 
              color=label_color_list[i])

(lưu ý: Tôi đã thêm 100 nên nó không hoàn toàn ở dưới cùng)

Để có được một kết quả như thế này: nhập mô tả hình ảnh ở đây


Chắc chắn v == labels[i]và vì vậy dòng thứ ba và thứ tư có thể đơn giản là 101, v?
Không phải đâu.

14

Tôi biết đó là một chủ đề cũ, nhưng tôi đã hạ cánh ở đây vài lần qua Google và nghĩ rằng chưa có câu trả lời nào thực sự hài lòng. Hãy thử sử dụng một trong các chức năng sau:

CHỈNH SỬA : Vì tôi đang nhận được một số lượt thích trên chủ đề cũ này, tôi cũng muốn chia sẻ một giải pháp cập nhật (về cơ bản đặt hai chức năng trước đây của tôi lại với nhau và tự động quyết định xem đó là biểu đồ thanh hay biểu đồ hbar):

def label_bars(ax, bars, text_format, **kwargs):
    """
    Attaches a label on every bar of a regular or horizontal bar chart
    """
    ys = [bar.get_y() for bar in bars]
    y_is_constant = all(y == ys[0] for y in ys)  # -> regular bar chart, since all all bars start on the same y level (0)

    if y_is_constant:
        _label_bar(ax, bars, text_format, **kwargs)
    else:
        _label_barh(ax, bars, text_format, **kwargs)


def _label_bar(ax, bars, text_format, **kwargs):
    """
    Attach a text label to each bar displaying its y value
    """
    max_y_value = ax.get_ylim()[1]
    inside_distance = max_y_value * 0.05
    outside_distance = max_y_value * 0.01

    for bar in bars:
        text = text_format.format(bar.get_height())
        text_x = bar.get_x() + bar.get_width() / 2

        is_inside = bar.get_height() >= max_y_value * 0.15
        if is_inside:
            color = "white"
            text_y = bar.get_height() - inside_distance
        else:
            color = "black"
            text_y = bar.get_height() + outside_distance

        ax.text(text_x, text_y, text, ha='center', va='bottom', color=color, **kwargs)


def _label_barh(ax, bars, text_format, **kwargs):
    """
    Attach a text label to each bar displaying its y value
    Note: label always outside. otherwise it's too hard to control as numbers can be very long
    """
    max_x_value = ax.get_xlim()[1]
    distance = max_x_value * 0.0025

    for bar in bars:
        text = text_format.format(bar.get_width())

        text_x = bar.get_width() + distance
        text_y = bar.get_y() + bar.get_height() / 2

        ax.text(text_x, text_y, text, va='center', **kwargs)

Bây giờ bạn có thể sử dụng chúng cho các ô thanh thông thường:

fig, ax = plt.subplots((5, 5))
bars = ax.bar(x_pos, values, width=0.5, align="center")
value_format = "{:.1%}"  # displaying values as percentage with one fractional digit
label_bars(ax, bars, value_format)

hoặc đối với các ô thanh ngang:

fig, ax = plt.subplots((5, 5))
horizontal_bars = ax.barh(y_pos, values, width=0.5, align="center")
value_format = "{:.1%}"  # displaying values as percentage with one fractional digit
label_bars(ax, horizontal_bars, value_format)

14

Sử dụng plt.text () để đưa văn bản vào cốt truyện.

Thí dụ:

import matplotlib.pyplot as plt
N = 5
menMeans = (20, 35, 30, 35, 27)
ind = np.arange(N)

#Creating a figure with some fig size
fig, ax = plt.subplots(figsize = (10,5))
ax.bar(ind,menMeans,width=0.4)
#Now the trick is here.
#plt.text() , you need to give (x,y) location , where you want to put the numbers,
#So here index will give you x pos and data+1 will provide a little gap in y axis.
for index,data in enumerate(menMeans):
    plt.text(x=index , y =data+1 , s=f"{data}" , fontdict=dict(fontsize=20))
plt.tight_layout()
plt.show()

Điều này sẽ hiển thị hình như:

biểu đồ thanh với các giá trị ở trên cùng


Dù sao để chuyển văn bản một chút sang trái?
S.Ramjit

1
@ S.Ramjitplt.text(x=index , y =data+1 , s=f"{data}" , fontdict=dict(fontsize=20), va='center')
theGtknerd

10

Đối với những người gấu trúc:

ax = s.plot(kind='barh') # s is a Series (float) in [0,1]
[ax.text(v, i, '{:.2f}%'.format(100*v)) for i, v in enumerate(s)];

Đó là nó. Ngoài ra, đối với những người thích applylặp lại quá nhiều với liệt kê:

it = iter(range(len(s)))
s.apply(lambda x: ax.text(x, next(it),'{:.2f}%'.format(100*x)));

Ngoài ra, ax.patchessẽ cung cấp cho bạn các thanh mà bạn sẽ nhận được ax.bar(...). Trong trường hợp bạn muốn áp dụng các chức năng của @SaturnFromTitan hoặc các kỹ thuật của người khác.


Vui lòng kiểm tra xem i, v có bị đảo ngược không. Có lẽ nó phải được[ax.text(i, v, '{:.2f}%'.format(100*v)) for i, v in enumerate(s)];
Jairo Alves

@JairoĐây là biểu đồ thanh ngang và v đại diện cho vị trí trên trục x, vì vậy nó phải chính xác. Vui lòng xem thêm câu trả lời được chấp nhận.
tozCSS

Ví dụ với các bản vá for p in ax.patches: ax.annotate(str(p.get_height()), (p.get_x() * 1.005, p.get_height() * 1.005))
Ichta

1

Tôi cũng cần nhãn thanh, lưu ý rằng trục y của tôi đang có chế độ xem được thu phóng sử dụng các giới hạn trên trục y. Các tính toán mặc định để đặt các nhãn lên đầu thanh vẫn hoạt động khi sử dụng chiều cao (use_global_coosystem = False trong ví dụ). Nhưng tôi muốn chứng minh rằng các nhãn cũng có thể được đặt ở dưới cùng của biểu đồ trong chế độ xem được thu phóng bằng cách sử dụng tọa độ toàn cục trong matplotlib 3.0.2 . Hy vọng nó sẽ giúp một ai đó.

def autolabel(rects,data):
"""
Attach a text label above each bar displaying its height
"""
c = 0
initial = 0.091
offset = 0.205
use_global_coordinate = True

if use_global_coordinate:
    for i in data:        
        ax.text(initial+offset*c, 0.05, str(i), horizontalalignment='center',
                verticalalignment='center', transform=ax.transAxes,fontsize=8)
        c=c+1
else:
    for rect,i in zip(rects,data):
        height = rect.get_height()
        ax.text(rect.get_x() + rect.get_width()/2., height,str(i),ha='center', va='bottom')

Ví dụ đầu ra


0

Tôi đã cố gắng làm điều này với các thanh âm mưu xếp chồng lên nhau. Mã đã làm việc cho tôi là.

# Code to plot. Notice the variable ax.
ax = df.groupby('target').count().T.plot.bar(stacked=True, figsize=(10, 6))
ax.legend(bbox_to_anchor=(1.1, 1.05))

# Loop to add on each bar a tag in position
for rect in ax.patches:
    height = rect.get_height()
    ypos = rect.get_y() + height/2
    ax.text(rect.get_x() + rect.get_width()/2., ypos,
            '%d' % int(height), ha='center', va='bottom')

0

Kiểm tra liên kết này Thư viện Matplotlib Đây là cách tôi sử dụng đoạn mã của nhãn tự động.

    def autolabel(rects):
    """Attach a text label above each bar in *rects*, displaying its height."""
    for rect in rects:
        height = rect.get_height()
        ax.annotate('{}'.format(height),
                    xy=(rect.get_x() + rect.get_width() / 2, height),
                    xytext=(0, 3),  # 3 points vertical offset
                    textcoords="offset points",
                    ha='center', va='bottom')
        
temp = df_launch.groupby(['yr_mt','year','month'])['subs_trend'].agg(subs_count='sum').sort_values(['year','month']).reset_index()
_, ax = plt.subplots(1,1, figsize=(30,10))
bar = ax.bar(height=temp['subs_count'],x=temp['yr_mt'] ,color ='g')
autolabel(bar)

ax.set_title('Monthly Change in Subscribers from Launch Date')
ax.set_ylabel('Subscriber Count Change')
ax.set_xlabel('Time')
plt.show()
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.