Matplotlib 플롯 효과적으로 주석 달기

Beginner

This tutorial is from open-source community. Access the source code

소개

이 랩에서는 Matplotlib 에서 플롯에 주석을 다는 방법을 안내합니다. 특정 관심 지점을 강조 표시하고 이러한 지점에 주의를 환기하기 위해 다양한 시각적 도구를 사용하는 방법을 배우게 됩니다. 주석 및 텍스트 도구는 정보를 전달하고 플롯을 시각적으로 더욱 매력적으로 만드는 데 필수적입니다.

VM 팁

VM 시작이 완료되면 왼쪽 상단을 클릭하여 Notebook 탭으로 전환하여 실습을 위해 Jupyter Notebook에 액세스하십시오.

때로는 Jupyter Notebook 이 로딩을 완료하는 데 몇 초 정도 기다려야 할 수 있습니다. Jupyter Notebook 의 제한 사항으로 인해 작업의 유효성 검사는 자동화할 수 없습니다.

학습 중에 문제가 발생하면 언제든지 Labby 에게 문의하십시오. 세션 후 피드백을 제공해주시면 즉시 문제를 해결해 드리겠습니다.

텍스트 포인트 및 주석 포인트 지정

이 점에 주석을 달려면 주석 포인트 xy=(x, y)를 지정해야 합니다. 또한, 이 주석에 대한 텍스트 위치에 대한 텍스트 포인트 xytext=(x, y)를 지정할 수 있습니다. 선택적으로, xycoordstextcoords에 대해 다음 문자열 중 하나를 사용하여 xyxytext의 좌표계를 지정할 수 있습니다 (기본값은 'data'입니다).

  • 'figure points' : 그림의 왼쪽 하단 모서리에서 점
  • 'figure pixels' : 그림의 왼쪽 하단 모서리에서 픽셀
  • 'figure fraction' : (0, 0) 은 그림의 왼쪽 하단이고 (1, 1) 은 오른쪽 상단입니다.
  • 'axes points' : 축의 왼쪽 하단 모서리에서 점
  • 'axes pixels' : 축의 왼쪽 하단 모서리에서 픽셀
  • 'axes fraction' : (0, 0) 은 축의 왼쪽 하단이고 (1, 1) 은 오른쪽 상단입니다.
  • 'offset points' : xy 값에서 오프셋 (포인트) 을 지정합니다.
  • 'offset pixels' : xy 값에서 오프셋 (픽셀) 을 지정합니다.
  • 'data' : 축 데이터 좌표계를 사용합니다.

참고: 물리적 좌표계 (점 또는 픽셀) 의 경우 원점은 그림 또는 축의 (아래쪽, 왼쪽) 입니다.

선택적으로, 화살표 속성을 지정하여 텍스트에서 주석이 달린 점까지 화살표를 그릴 수 있습니다. 화살표 속성의 딕셔너리를 제공합니다. 유효한 키는 다음과 같습니다.

  • width: 포인트 단위의 화살표 너비
  • frac: 머리가 차지하는 화살표 길이의 비율
  • headwidth: 포인트 단위의 화살표 머리 밑면 너비
  • shrink: 주석이 달린 점과 텍스트에서 팁과 밑면을 몇 퍼센트 이동합니다.
  • any key for matplotlib.patches.polygon (예: facecolor)
import matplotlib.pyplot as plt
import numpy as np

from matplotlib.patches import Ellipse
from matplotlib.text import OffsetFrom

## Create our figure and data we'll use for plotting
fig, ax = plt.subplots(figsize=(4, 4))

t = np.arange(0.0, 5.0, 0.01)
s = np.cos(2*np.pi*t)

## Plot a line and add some simple annotations
line, = ax.plot(t, s)
ax.annotate('figure pixels',
            xy=(10, 10), xycoords='figure pixels')
ax.annotate('figure points',
            xy=(107, 110), xycoords='figure points',
            fontsize=12)
ax.annotate('figure fraction',
            xy=(.025, .975), xycoords='figure fraction',
            horizontalalignment='left', verticalalignment='top',
            fontsize=20)

## The following examples show off how these arrows are drawn.

ax.annotate('point offset from data',
            xy=(3, 1), xycoords='data',
            xytext=(-10, 90), textcoords='offset points',
            arrowprops=dict(facecolor='black', shrink=0.05),
            horizontalalignment='center', verticalalignment='bottom')

ax.annotate('axes fraction',
            xy=(2, 1), xycoords='data',
            xytext=(0.36, 0.68), textcoords='axes fraction',
            arrowprops=dict(facecolor='black', shrink=0.05),
            horizontalalignment='right', verticalalignment='top')

## You may also use negative points or pixels to specify from (right, top).
## E.g., (-10, 10) is 10 points to the left of the right side of the axes and 10
## points above the bottom

ax.annotate('pixel offset from axes fraction',
            xy=(1, 0), xycoords='axes fraction',
            xytext=(-20, 20), textcoords='offset pixels',
            horizontalalignment='right',
            verticalalignment='bottom')

ax.set(xlim=(-1, 5), ylim=(-3, 5))

여러 좌표계 및 축 유형 사용

xypointxytext를 서로 다른 위치와 좌표계로 지정할 수 있으며, 선택적으로 연결선 (connecting line) 을 켜고 마커로 점을 표시할 수 있습니다. 주석은 극좌표 축 (polar axes) 에서도 작동합니다.

fig, ax = plt.subplots(subplot_kw=dict(projection='polar'), figsize=(3, 3))
r = np.arange(0, 1, 0.001)
theta = 2*2*np.pi*r
line, = ax.plot(theta, r)

ind = 800
thisr, thistheta = r[ind], theta[ind]
ax.plot([thistheta], [thisr], 'o')
ax.annotate('a polar annotation',
            xy=(thistheta, thisr),  ## theta, radius
            xytext=(0.05, 0.05),    ## fraction, fraction
            textcoords='figure fraction',
            arrowprops=dict(facecolor='black', shrink=0.05),
            horizontalalignment='left',
            verticalalignment='bottom')

화살표 및 버블 스타일 사용자 정의

xytext와 주석 포인트 사이의 화살표, 그리고 주석 텍스트를 덮는 버블은 고도로 사용자 정의할 수 있습니다. 아래는 몇 가지 매개변수 옵션과 그 결과 출력입니다.

fig, ax = plt.subplots(figsize=(8, 5))

t = np.arange(0.0, 5.0, 0.01)
s = np.cos(2*np.pi*t)
line, = ax.plot(t, s, lw=3)

ax.annotate(
    'straight',
    xy=(0, 1), xycoords='data',
    xytext=(-50, 30), textcoords='offset points',
    arrowprops=dict(arrowstyle="->"))
ax.annotate(
    'arc3,\nrad 0.2',
    xy=(0.5, -1), xycoords='data',
    xytext=(-80, -60), textcoords='offset points',
    arrowprops=dict(arrowstyle="->",
                    connectionstyle="arc3,rad=.2"))
ax.annotate(
    'arc,\nangle 50',
    xy=(1., 1), xycoords='data',
    xytext=(-90, 50), textcoords='offset points',
    arrowprops=dict(arrowstyle="->",
                    connectionstyle="arc,angleA=0,armA=50,rad=10"))
ax.annotate(
    'arc,\narms',
    xy=(1.5, -1), xycoords='data',
    xytext=(-80, -60), textcoords='offset points',
    arrowprops=dict(
        arrowstyle="->",
        connectionstyle="arc,angleA=0,armA=40,angleB=-90,armB=30,rad=7"))
ax.annotate(
    'angle,\nangle 90',
    xy=(2., 1), xycoords='data',
    xytext=(-70, 30), textcoords='offset points',
    arrowprops=dict(arrowstyle="->",
                    connectionstyle="angle,angleA=0,angleB=90,rad=10"))
ax.annotate(
    'angle3,\nangle -90',
    xy=(2.5, -1), xycoords='data',
    xytext=(-80, -60), textcoords='offset points',
    arrowprops=dict(arrowstyle="->",
                    connectionstyle="angle3,angleA=0,angleB=-90"))
ax.annotate(
    'angle,\nround',
    xy=(3., 1), xycoords='data',
    xytext=(-60, 30), textcoords='offset points',
    bbox=dict(boxstyle="round", fc="0.8"),
    arrowprops=dict(arrowstyle="->",
                    connectionstyle="angle,angleA=0,angleB=90,rad=10"))
ax.annotate(
    'angle,\nround4',
    xy=(3.5, -1), xycoords='data',
    xytext=(-70, -80), textcoords='offset points',
    size=20,
    bbox=dict(boxstyle="round4,pad=.5", fc="0.8"),
    arrowprops=dict(arrowstyle="->",
                    connectionstyle="angle,angleA=0,angleB=-90,rad=10"))
ax.annotate(
    'angle,\nshrink',
    xy=(4., 1), xycoords='data',
    xytext=(-60, 30), textcoords='offset points',
    bbox=dict(boxstyle="round", fc="0.8"),
    arrowprops=dict(arrowstyle="->",
                    shrinkA=0, shrinkB=10,
                    connectionstyle="angle,angleA=0,angleB=90,rad=10"))
## You can pass an empty string to get only annotation arrows rendered
ax.annotate('', xy=(4., 1.), xycoords='data',
            xytext=(4.5, -1), textcoords='data',
            arrowprops=dict(arrowstyle="<->",
                            connectionstyle="bar",
                            ec="k",
                            shrinkA=5, shrinkB=5))

ax.set(xlim=(-1, 5), ylim=(-4, 3))

좌표계의 추가 예시

아래에서는 몇 가지 더 많은 좌표계 예시와 주석의 위치를 지정하는 방법을 보여줍니다.

fig, (ax1, ax2) = plt.subplots(1, 2)

bbox_args = dict(boxstyle="round", fc="0.8")
arrow_args = dict(arrowstyle="->")

## Here we'll demonstrate the extents of the coordinate system and how
## we place annotating text.

ax1.annotate('figure fraction : 0, 0', xy=(0, 0), xycoords='figure fraction',
             xytext=(20, 20), textcoords='offset points',
             ha="left", va="bottom",
             bbox=bbox_args,
             arrowprops=arrow_args)

ax1.annotate('figure fraction : 1, 1', xy=(1, 1), xycoords='figure fraction',
             xytext=(-20, -20), textcoords='offset points',
             ha="right", va="top",
             bbox=bbox_args,
             arrowprops=arrow_args)

ax1.annotate('axes fraction : 0, 0', xy=(0, 0), xycoords='axes fraction',
             xytext=(20, 20), textcoords='offset points',
             ha="left", va="bottom",
             bbox=bbox_args,
             arrowprops=arrow_args)

ax1.annotate('axes fraction : 1, 1', xy=(1, 1), xycoords='axes fraction',
             xytext=(-20, -20), textcoords='offset points',
             ha="right", va="top",
             bbox=bbox_args,
             arrowprops=arrow_args)

## It is also possible to generate draggable annotations

an1 = ax1.annotate('Drag me 1', xy=(.5, .7), xycoords='data',
                   ha="center", va="center",
                   bbox=bbox_args)

an2 = ax1.annotate('Drag me 2', xy=(.5, .5), xycoords=an1,
                   xytext=(.5, .3), textcoords='axes fraction',
                   ha="center", va="center",
                   bbox=bbox_args,
                   arrowprops=dict(patchB=an1.get_bbox_patch(),
                                   connectionstyle="arc3,rad=0.2",
                                   **arrow_args))
an1.draggable()
an2.draggable()

an3 = ax1.annotate('', xy=(.5, .5), xycoords=an2,
                   xytext=(.5, .5), textcoords=an1,
                   ha="center", va="center",
                   bbox=bbox_args,
                   arrowprops=dict(patchA=an1.get_bbox_patch(),
                                   patchB=an2.get_bbox_patch(),
                                   connectionstyle="arc3,rad=0.2",
                                   **arrow_args))

## Finally we'll show off some more complex annotation and placement

text = ax2.annotate('xy=(0, 1)\nxycoords=("data", "axes fraction")',
                    xy=(0, 1), xycoords=("data", 'axes fraction'),
                    xytext=(0, -20), textcoords='offset points',
                    ha="center", va="top",
                    bbox=bbox_args,
                    arrowprops=arrow_args)

ax2.annotate('xy=(0.5, 0)\nxycoords=artist',
             xy=(0.5, 0.), xycoords=text,
             xytext=(0, -20), textcoords='offset points',
             ha="center", va="top",
             bbox=bbox_args,
             arrowprops=arrow_args)

ax2.annotate('xy=(0.8, 0.5)\nxycoords=ax1.transData',
             xy=(0.8, 0.5), xycoords=ax1.transData,
             xytext=(10, 10),
             textcoords=OffsetFrom(ax2.bbox, (0, 0), "points"),
             ha="left", va="bottom",
             bbox=bbox_args,
             arrowprops=arrow_args)

ax2.set(xlim=[-2, 2], ylim=[-2, 2])

요약

이 랩에서는 Matplotlib 에서 플롯에 주석을 다는 기본적인 사항을 다루었습니다. 주석 및 텍스트 포인트를 지정하는 방법, 여러 좌표계 및 축 유형을 사용하는 방법, 화살표 및 버블 스타일을 사용자 정의하는 방법, 그리고 더 많은 좌표계 예시를 배웠습니다. 이러한 도구는 플롯을 시각적으로 더 매력적으로 만들고 정보를 효과적으로 전달하는 데 필수적입니다.