Python matplotlib : arrow (화살표 그리기, 좌표평면 화살표)
matplotlib의 arrow method는 좌표평면에 화살표를 그릴 수 있도록 해줍니다.
import matplotlib.pyplot as plt
plt.arrow(
x=1, y=1, # 화살표 시작 지점의 x, y 좌표 (화살표 tail의 x, y 좌표)
dx=2.5, dy=0.3, # 화살표 시작 지점 으로부터 x축으로 얼마, y축으로 얼마나 이동한 화살표를 그릴지를 의미
width=0.01, # 화살표 두께
length_includes_head=True, # 화살표 길이를 잴 때 head의 길이도 포함할지 여부 (True = 화살표 head 길이도 화살표 전체 길이에 포함하여 고려)
head_width=0.03, # 화살표 head의 두께
head_length=0.1, # 화살표 head의 길이
overhang=0, # 화살표 head의 표시 (0이면 head가 삼각형이고, 1에 가까울 수록 선에 가까워짐)
linestyle='--', # 테두리 line style = {'-', '--', '-.', ':', '', ...}
linewidth=1, # 테두리 line 두께
edgecolor='black', # 테두리 색상
facecolor='lightblue', # 화살표 색상
alpha=1, # 투명도 (0 = 완전한 투명, 1 = 완전한 불투명)
)
plt.show()
위 코드를 실행해봅시다.
위처럼 좌표평면에 화살표가 그려졌습니다.
각 옵션의 의미는 코드에 주석으로 적어놓았습니다.
한가지 color 옵션은 주의를 해서 사용해야 합니다.
import matplotlib.pyplot as plt
plt.arrow(
x=1, y=1, # 화살표 시작 지점의 x, y 좌표 (화살표 tail의 x, y 좌표)
dx=2.5, dy=0.3, # 화살표 시작 지점 으로부터 x축으로 얼마, y축으로 얼마나 이동한 화살표를 그릴지를 의미
width=0.01, # 화살표 두께
length_includes_head=True, # 화살표 길이를 잴 때 head의 길이도 포함할지 여부 (True = 화살표 head 길이도 포함)
head_width=0.03, # 화살표 head의 두께
head_length=0.1, # 화살표 head의 길이
overhang=0, # 화살표 head의 표시 (0이면 head가 삼각형이고, 1에 가까울 수록 선에 가까워짐)
linestyle='--', # 테두리 line style = {'-', '--', '-.', ':', '', ...}
linewidth=1, # 테두리 line 두께
color='black', # 화살표 & 테두리 색상
# edgecolor='black', # 테두리 색상
# facecolor='lightblue', # 화살표 색상
alpha=1, # 투명도 (0 = 완전한 투명, 1 = 완전한 불투명)
)
plt.show()
위 예시에선 edgecolor, facecolor 대신에 color 옵션만을 사용했습니다.
color='black' 으로 설정했기 때문에
화살표 색상과 테두리 색상이 모두 검은색으로 설정된 것을 볼 수 있습니다.
이렇듯 color 옵션은 화살표의 색상과 화살표 테두리의 색상을 동시에 설정합니다.
그렇기에 color 옵션은 edgecolor, facecolor 옵션과 동시에 사용될 수 없습니다.
color옵션을 사용하려면 edgecolor, facecolor 옵션을 지워야 합니다.
subplot에서 사용하는 arrow는 좀 방식이 다릅니다.
아래 코드를 봅시다.
import matplotlib.pyplot as plt
from matplotlib.patches import FancyArrowPatch
fig, graph = plt.subplots(nrows=2, ncols=1)
cls_arrow_1 = FancyArrowPatch(
posA=(1, 1), # arrow tail (x, y)
posB=(3, 2), # arrow head (x, y)
arrowstyle='simple', # arrow style
linestyle='-', # line style = {'-', '--', '-.', ':', ''}
linewidth=2, # line width
mutation_scale=100, # 화살표 scale
color='pink', # 테두리 & 화살표 색상
)
cls_arrow_2 = FancyArrowPatch(
posA=(1, 1), # arrow tail (x, y)
posB=(3, 2), # arrow head (x, y)
arrowstyle='simple', # arrow style
linestyle='-', # line style = {'-', '--', '-.', ':', ''}
linewidth=2, # line width
mutation_scale=100, # 화살표 scale
edgecolor='gray', # 테두리 색상
facecolor='lightblue' # 화살표 색상
)
graph[0].add_patch(cls_arrow_1)
graph[1].add_patch(cls_arrow_2)
graph[0].set_xlim(0, 4)
graph[0].set_ylim(0, 3)
graph[1].set_xlim(0, 4)
graph[1].set_ylim(0, 3)
plt.show()
결과를 보면 각각의 subplot에 화살표가 그려진 것을 볼 수 있습니다.
코드를 보면 subplot에서 화살표를 그리기 위해선
FancyArrowPatch를 이용하여 arrow patch class를 생성한 후
add_patch method를 이용해 이러한 patch class를 추가해주면 됩니다.
각각의 parameter가 의미하는 바는 코드에 주석으로 적어놓았습니다.
여기서 주의할 점은 크게 2가지가 있습니다.
cls_arrow_1과 cls_arrow_2를 보면 차이점이 있습니다.
그 중 하나는 color입니다.
cls_arrow_1에는 color 옵션을 사용하고 있으며
cls_arrow_2에는 edgecolor, facecolor 옵션을 사용하고 있습니다.
이 글의 첫 예시에서와 마찬가지로 color 옵션은 테두리 색상과 화살표 색상을 동시에 결정하기 때문에
color 옵션은 edgecolor, facecolor 옵션과 동시에 사용할 수 없습니다.
두 번째 주의할 점은 mutation_scale입니다.
mutation_scale은 화살표의 scale을 얼마나 확대하여 나타낼지를 의미합니다.
화살표의 tail, head 지점이 결정되어도 그 지점 내에서 화살표를 얼마나 확대해서 나타낼지, 얼마나 축소해서 나타낼지는 다를 수 있다.
따라서 mutation_scale이 제대로 지정되지 않을 경우 제대로 화살표가 표시되지 않을 수 있습니다.
이렇듯 mutation_scale은 반드시 명시되어야 하며
만약 mutation_scale 옵션을 생략하고 코드를 실행하면 화살표가 제대로 그려지지 않는 것을 볼 수 있을 것입니다.
arrow style option은 arrow의 모양을 결정하는데
위 링크를 참고하면 다양한 arrow style을 볼 수 있습니다.
그 내용은 다음과 같습니다.
arrowstyle 옵션에 사용할 수 있는 keyword는 아래 table의 Name column에 있는 값입니다.
Class | Name | Attrs |
Curve | - | None |
CurveA | <- | head_length=0.4, head_width=0.2, widthA=1.0, widthB=1.0, lengthA=0.2, lengthB=0.2, angleA=0, angleB=0, scaleA=None, scaleB=None |
CurveB | -> | head_length=0.4, head_width=0.2, widthA=1.0, widthB=1.0, lengthA=0.2, lengthB=0.2, angleA=0, angleB=0, scaleA=None, scaleB=None |
CurveAB | <-> | head_length=0.4, head_width=0.2, widthA=1.0, widthB=1.0, lengthA=0.2, lengthB=0.2, angleA=0, angleB=0, scaleA=None, scaleB=None |
CurveFilledA | <|- | head_length=0.4, head_width=0.2, widthA=1.0, widthB=1.0, lengthA=0.2, lengthB=0.2, angleA=0, angleB=0, scaleA=None, scaleB=None |
CurveFilledB | -|> | head_length=0.4, head_width=0.2, widthA=1.0, widthB=1.0, lengthA=0.2, lengthB=0.2, angleA=0, angleB=0, scaleA=None, scaleB=None |
CurveFilledAB | <|-|> | head_length=0.4, head_width=0.2, widthA=1.0, widthB=1.0, lengthA=0.2, lengthB=0.2, angleA=0, angleB=0, scaleA=None, scaleB=None |
BracketA | ]- | widthA=1.0, lengthA=0.2, angleA=0 |
BracketB | -[ | widthB=1.0, lengthB=0.2, angleB=0 |
BracketAB | ]-[ | widthA=1.0, lengthA=0.2, angleA=0, widthB=1.0, lengthB=0.2, angleB=0 |
BarAB | |-| | widthA=1.0, angleA=0, widthB=1.0, angleB=0 |
BracketCurve | ]-> | widthA=1.0, lengthA=0.2, angleA=None |
CurveBracket | <-[ | widthB=1.0, lengthB=0.2, angleB=None |
Simple | simple | head_length=0.5, head_width=0.5, tail_width=0.2 |
Fancy | fancy | head_length=0.4, head_width=0.4, tail_width=0.4 |
Wedge | wedge | tail_width=0.3, shrink_factor=0.5 |
아래 코드는 두 가지 arrowstyle을 적용한 예시입니다.
import matplotlib.pyplot as plt
from matplotlib.patches import FancyArrowPatch
fig, graph = plt.subplots(nrows=2, ncols=1)
cls_arrow_1 = FancyArrowPatch(
posA=(1, 1), # arrow tail (x, y)
posB=(3, 2), # arrow head (x, y)
arrowstyle='<->', # arrow style
linestyle='-', # line style = {'-', '--', '-.', ':', ''}
linewidth=2, # line width
mutation_scale=100, # 화살표 scale
color='pink', # 테두리 & 화살표 색상
)
cls_arrow_2 = FancyArrowPatch(
posA=(1, 1), # arrow tail (x, y)
posB=(3, 2), # arrow head (x, y)
arrowstyle=']->', # arrow style
linestyle='-', # line style = {'-', '--', '-.', ':', ''}
linewidth=1, # line width
mutation_scale=30, # 화살표 scale
edgecolor='gray', # 테두리 색상
facecolor='lightblue' # 화살표 색상
)
graph[0].add_patch(cls_arrow_1)
graph[1].add_patch(cls_arrow_2)
graph[0].set_xlim(0, 4)
graph[0].set_ylim(0, 3)
graph[1].set_xlim(0, 4)
graph[1].set_ylim(0, 3)
plt.show()
결과를 보면 내가 지정한 대로 화살표의 모양이 정해진 것을 알 수 있습니다.