

간혹 인터넷을 돌아다니다보면서 이런 그림을 보게 되는 경우가 있다.
이런 그림을 이른바 생키 다이어그램(Sankey Diagram)이라고 한다. 기업의 매출, 수익 및 비용을 표시한 재무제표의 손익계산서를 시각화한 그림으로, 기업의 수익구조를 표보다 훨씬 직관적으로 표현해준다. 생키 다이어그램은 이런 기업 손익계산서 뿐 아니라 물자 흐름, 물량 변화 등을 표시하는 다양한 상황에서 이용된다.
생키 다이어그램을 혹시 직접 만들어볼 수 있을까? 투자하고자하는 기업의 손익을 직관적으로 제시할 수도 있고, 또 개인의 경우 가계부의 현금 흐름을 파악하는데에도 유용하게 이용할 수 있다.
생키 다이어그램 제작을 지원하는 여러 사이트가 있다. 유용한 사이트는 대표적으로 https://www.sankeyart.com/등이 있다.
그러나 단일 기업이나 개인 가계에 대한 경우 등 같은 항목을 매번 반복하는 경우나, 위 사이트들에서 제공되는 사항에서 일부 커스터마이징이 필요한 경우에는 직접 코드를 작성해 시각화하는 것이 더 나을 수 있다.
그런데 검색창에 이를 위한 코드를 검색해봐도 친절하게 소개된 글이 없어 익히기가 쉽지 않았다.
이 글에서는 생키 다이어그램을 파이썬 코드를 이용해 클론코딩하며 한번 Sankey Diagram을 만드는 과정을 파악해보려고 한다.
파이썬의 시각화 라이브러리 중, Plotly가 생키 다이어그램 기능을 제공한다. 이 라이브러리 기능을 이용해 한번 Sankey diagram을 코딩해보자. 예제로는 글 맨 위의 넷플릭스 자료를 한번 이용해보려고 한다.
plotly의 sankey diagram 기능을 이용하려면 우선 용어를 알아야한다.

먼저 각 항목에 해당하는 직사각형은 Node로 지칭된다. 그리고, node 사이를 연결하는 흐름은 link로 지칭된다.

각각의 link는 두개 node를 연결하는데, 이 중 출발점을 source, 도착점을 target으로 지칭한다.
이제 필요한 것을 모두 알았으니 직접 코드를 살펴보자.
import plotly.graph_objects as go ###우선 plotly를 불러온다.
nodes =
["U.S & Canada", "Europe, M. East, Africa", "Latin America", "Asia-Pacific", "Revenue", "Gross profit", "Cost of revenue", "Operating profit", "Operating cost", "Net profit", "Tax", "Interest", "Marketing", "Tech & Dev", "G&A"]
### 우선 그림에 존재하는 모든 node를 정의한다.
제일 먼저 해야할 일은 각각의 node를 지정해주는 것이다. node는 작성 순서대로 0부터 번호를 할당받는다.
# link 속성 지정
links = {
'source': [0, 1, 2, 3, 4, 4, 5, 5, 7, 7, 7, 8, 8, 8], # 각 link의 source가 되는 노드 번호를 적는다.
'target': [4, 4, 4, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14], # target이 되는 노드 번호를 적는다.
'value': [4300, 3000, 1200, 1100, 4400, 5200, 2600, 1800, 2100, 400, 89, 600, 700, 400], # 각 node에 해당하는 값을 적어준다. 이 수치는 노드의 높이가 된다.
'color': ["#BBBBBB", "#BBBBBB", "#BBBBBB", "#BBBBBB", "#B2D4B3", "#DD9FAA", "#B2D4B3", "#DD9FAA", "#B2D4B3", "#DD9FAA", "#DD9FAA", "#DD9FAA", "#DD9FAA", "#DD9FAA"] # 각 link의 색상을 지정한다.
}
다음이 가장 핵심이 된다. 각 node를 연결하는 link를 정의해주면 된다. 예를 들어 첫번째 link(0번 링크라고 하자)는 0번 노드에서 출발하여 4번 노드로 도착하는, 4300 값을 가지는 회색 링크가 된다. 이런 식으로 모든 링크의 속성을 지정해주면 된다.

node를 좌측 위에서부터 아래로 번호를 붙여나가고, 링크도 같은 순서로 번호를 붙여나간다고 생각하면 된다.
node_colors = ["#696969", "#696969", "#696969", "#696969", "#696969", "#55A056", "#B52B43", "#55A056", "#B52B43", "#55A056", "#B52B43", "#B52B43", "#B52B43", "#B52B43", "#B52B43"]
다음으로는 node의 색도 각각 지정해준다.
#plotly의 sankey를 이용해 diagram을 작성한다.
fig = go.Figure(go.Sankey(
node = {
"pad": 15, "thickness": 20, "color": node_colors, #정의된 node_colors를 각 node의 색상으로 배정한다.
"label": nodes, #미리 작성해둔 nodes를 지정한다.
"line": {"color": "rgba(0, 0, 0, 0)", "width": 0} #line을 없앤다. },
link = { "source": links['source'], "target": links['target'], "value": links['value'], "color": links['color'] # 미리 작성해둔 속성들을 배정한다. } ))
# 이름 지정 등 기타 레이아웃 설정
fig.update_layout(title_text="Netflix Q2 FY24 Income Statement", font_size=10, height=400, width=700, autosize=False, margin=dict(l=100, r=100, t=100, b=100), # Margins around the plot area plot_bgcolor='rgba(0,0,0,0)')
fig.show()
이후로는 plotly를 이용해 그래프를 작성해주면 된다.
전체 코드는 아래와 같다.
import plotly.graph_objects as go
nodes = ["U.S & Canada", "Europe, M. East, Africa", "Latin America", "Asia-Pacific", "Revenue", "Gross profit", "Cost of revenue", "Operating profit", "Operating cost", "Net profit", "Tax", "Interest", "Marketing", "Tech & Dev", "G&A"]
links = {
'source': [0, 1, 2, 3, 4, 4, 5, 5, 7, 7, 7, 8, 8, 8],
'target': [4, 4, 4, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14],
'value': [4300, 3000, 1200, 1100, 4400, 5200, 2600, 1800, 2100, 400, 89, 600, 700, 400],
'color': ["#BBBBBB", "#BBBBBB", "#BBBBBB", "#BBBBBB", "#B2D4B3", "#DD9FAA", "#B2D4B3", "#DD9FAA", "#B2D4B3", "#DD9FAA", "#DD9FAA", "#DD9FAA", "#DD9FAA", "#DD9FAA"] }
}
node_colors = ["#696969", "#696969", "#696969", "#696969", "#696969", "#55A056", "#B52B43", "#55A056", "#B52B43", "#55A056", "#B52B43", "#B52B43", "#B52B43", "#B52B43", "#B52B43"]
fig = go.Figure(go.Sankey( node = { "pad": 15, "thickness": 20, "color": node_colors, "label": nodes, "line": {"color": "rgba(0, 0, 0, 0)", "width": 0} }, link = { "source": links['source'], "target": links['target'], "value": links['value'], "color": links['color'] } ))
fig.update_layout(title_text="Netflix Q2 FY24 Income Statement", font_size=10, height=400, width=700, autosize=False, margin=dict(l=100, r=100, t=100, b=100), plot_bgcolor='rgba(0,0,0,0)')
fig.show()
결과는 아래와 같다.

물론 세부적인 면에서는 여전히 좀 차이가 있지만, 대략적인 형태는 동일하게 클론했다. 위와 같은 방식으로 생키 다이어그램을 어렵지 않게 만들 수 있고, 한번 만들어두면 이후에는 Value만 바꿔가며 반복 생산할 수 있게 된다.
'프로그래밍 > Python' 카테고리의 다른 글
ColorBrewer - 데이터 시각화 색상표 팔레트 제공 사이트 (1) | 2024.09.15 |
---|
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!