Python/Python matplotlib

Python matplotlib : arrow (화살표 그리기, 좌표평면 화살표)

CosmosProject 2024. 4. 10. 02:41
728x90
반응형

 

 

 

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의 모양을 결정하는데

https://matplotlib.org/stable/api/_as_gen/matplotlib.patches.ArrowStyle.html#matplotlib.patches.Arrowstyle

 

matplotlib.patches.ArrowStyle — Matplotlib 3.8.4 documentation

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, scale

matplotlib.org

 

위 링크를 참고하면 다양한 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()

 

 

결과를 보면 내가 지정한 대로 화살표의 모양이 정해진 것을 알 수 있습니다.

 

 

 

 

 

728x90
반응형