[python] matplotlib 막대 차트에 값 레이블 추가

비교적 쉬울 것 같은 느낌이 들었습니다. 아래에 가져온 코드는 내가 작업중인 더 큰 프로젝트를 기반으로 한 샘플입니다. 모든 세부 사항을 게시 할 이유가 없었으므로 내가 가져온 데이터 구조를 그대로 수락하십시오.

기본적으로 막대 차트를 만들고 있으며 막대에 값 레이블을 추가하는 방법을 알아낼 수 있습니다 (막대 중앙 또는 바로 위에 있음). 웹에서 샘플을 보았지만 내 코드에서 성공하지 못했습니다. 나는 해결책이 ‘텍스트’또는 ‘주석’이라고 믿지만 나는 : a) 어떤 것을 사용할지 모른다 (그리고 일반적으로 말해서, 언제 어떤 것을 사용해야하는지 알지 못했다). b) 값 레이블을 표시 할 수 없습니다. 도움을 주시면 감사하겠습니다. 아래 코드. 미리 감사드립니다!

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)



답변

첫째 freq_series.plot축 반환 하지 인물 그래서 좀 더 내 대답을 내가 그것을 참조하기 위해 당신의 주어진 코드를 변경했습니다 취소 ax가 아닌 fig다른 코드 예제와 함께 일관성을 할 수 있습니다.

ax.patches멤버 로부터 플롯에 생성 된 막대 목록을 가져올 수 있습니다 . 그런 다음 matplotlib갤러리 예제 에 설명 된 기술을 사용하여 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')

이렇게하면 다음과 같은 레이블이 지정된 플롯이 생성됩니다.

여기에 이미지 설명 입력


답변

다른 질문에 대한이 답변 에서 언급 된 기능을 기반 으로 막대 차트에 레이블을 배치하는 데 매우 일반적으로 적용 가능한 솔루션을 찾았습니다.

안타깝게도 다른 솔루션은 레이블과 막대 사이의 간격이 막대의 절대 단위로 지정 되거나 막대 높이에 따라 조정 되기 때문에 많은 경우에서 작동하지 않습니다 . 전자는 좁은 범위의 값에 대해서만 작동하고 후자는 한 플롯 내에서 일관되지 않은 간격을 제공합니다. 둘 다 로그 축에서 잘 작동하지 않습니다.

내가 제안한 솔루션은 스케일 (즉, 작은 숫자와 큰 숫자)과는 독립적으로 작동 points하며 오프셋에 시각적 단위 를 사용하기 때문에 음수 값과 로그 스케일로 레이블을 올바르게 배치 합니다.

이러한 경우 레이블의 올바른 배치를 보여주기 위해 음수를 추가했습니다.

각 막대의 높이 값이 레이블로 사용됩니다. 다른 레이블은 Simon의 for rect, label in zip(rects, labels)snippet 과 함께 쉽게 사용할 수 있습니다 .

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

편집 : barnhillec이 제안한대로 함수에서 관련 기능을 추출했습니다 .

그러면 다음과 같은 출력이 생성됩니다.

각 막대에 레이블이 자동으로 배치 된 막대 차트

그리고 로그 스케일 (및 로그 스케일링을 보여주기 위해 입력 데이터에 대한 일부 조정)을 사용하면 결과는 다음과 같습니다.

각 막대에 자동으로 배치 된 레이블이있는 로그 눈금이있는 막대 차트


답변

위의 (훌륭한!) 답변을 바탕으로 몇 가지 조정만으로 수평 막대 그림을 만들 수도 있습니다.

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

주석이있는 수평 막대 그림


답변

막대 위의 데이터 포인트에 레이블을 지정하려면 plt.annotate ()를 사용할 수 있습니다.

내 코드 :

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

의 수평 및 수직 정렬을 지정함으로써 'center''bottom'각각 하나를 중심으로 얻을 수있는 주석.

레이블이있는 막대 차트


답변

막대 위에 데이터 포인트 만 추가하려는 경우 다음을 사용하여 쉽게 수행 할 수 있습니다.

 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


답변