오랜만의 Shiny 개발기

재무를 몰라서 그냥 차트 만드는 툴을 만들어버림

Jinhwan Kim
9 min readNov 12, 2022

여전히 집 밖을 많이 돌아다니는 요즘. 지하철에서 인터넷 서핑을 하다가 아래 같은 신기한 짤을 발견했다.

Genuine impact라는 곳에서 특정 기업의 재무 현황을 차트로 그려낸 건데, 보통 이런 차트를 생키 차트라고 부르는 것은 알고 있었고 사용도 했었지만 아래처럼 세부 그룹을 나누는 용도로만 사용했었지, 이렇게 단계로 나뉘는 흐름으로 보는 것은 신기했다 (생각해보니 퍼널로도 그릴 수 있고 예시도 있더라)

암튼 “와 개쩌네”라는 생각이 들었고 나도 그려봐야지 ~ 라는 생각으로 R을 켰지만, 결국 일이 커져서 이 글이 되었다 ㅋㅋ

처음에 사용하려고 했던 것은 ggsankey 였는데, 뭔가 구렸다. networkD3도 있긴 했지만 마찬가지로 뭔가 구려서 해매던 차에 PantaRhei 라는 패키지를 발견했다. (Everything flows라는 의미)

처음 구상은 종목코드 (ex CPNG )를 입력하면 미국 증권거래 위원회 (www.sec.gov/edgar)의 분기 혹은 반기 리포트를 조회하여 그 내부에서 Revenue 항목을 찾아 주요 수입 요소들 그리고 이후 재무 흐름을 자동으로 그려주는 어플리케이션을 생각했다.

피그마로 만듬. 닌텐도 차트는 genuin impact 가 그린 그림

문제는 조직마다 이 리포트의 형태가 조금씩 다르기 때문에 크롤링으로 해결 할 수 있는 부분이 상당히 적다는 것. (IR 담당자 맘대로 인가)

예를 들면 위 이미지의 주인공, APPL의 경우 아래처럼 Products and Services Performance 라는 항목으로 주력 제품들의 매출을 제공한다.

그러나 MSFT에서는 Products and Services Performance가 아닌 다른 형태로 제공한다.

그나마 공통적인 키워드라면 Revenue였고, 그 와중에도 이를 타고 가서 등장하는 몇개의 테이블들을 보고 그중 아 이건 매출 구성 요소구나 하는 것을 수동으로 찾아야만 했다. (어쩌면 구분 방법이 있을 수도 있지만 증권 업계를 몰라서 ㅎㅎ)

이러한 이유로 방향을 바꾸게 된 어플리케이션의 방향은 이러했다.

데이터 테이블은 (재무 지식이 가진) 사람이 준비하고 이를 넣어서 차트를 그릴 수 있는 어플리케이션

Sankey

Shiny 이야기를 하기 전에 PantaRhei 패키지에 대한 설명을 잠깐 하면 이러하다. (교수님이 만든거라 github 없이 CRAN에만 있음)

연결을 그려내는 생키차트의 특성상 데이터는 노드와 엣지 (flow라고 부른다) 가 필요하며, 노드는 ID와 노드가 위치할 좌표 (x, y)로 구성된다. 좌표를 입력 받는다는 것은 상당히 직관적이며, 아래 코드를 실행하면 나오는 그림은 이러하다

library(PantaRhei)
nodes <- data.frame(
ID = c('A', 'B'),
x = c(1, 2)
y = c(1, 3)
)

flows <- data.frame(
from = 'A',
to = 'B',
quantity = 10,
substance = 'gain'
)

colors <- data.frame(
substance = 'gain',
color = 'blue'
)

sankey(nodes, flows, colors)
초록색은 내가 추가한 가이드

사용자에게서 각 노드와, 엣지의 정보를 입력 받는 Shiny 어플리케이션은 금방 만들 수 있었고 초기 화면은 이러했다. 다만 너무 일렬로 되어있었기 때문에 약간의 UI를 고쳐서 오른쪽 그림의 형태를 만들었고, 이후 material을 뿌려 마지막 그림을 만들었다. (material을 뿌렸다 라는 한 문장으로 표현되었지만, 엄청난 노가다가 있었다…)

sankey with PantaRhei + Shiny

PantaRhei

여기에서 해피엔딩이면 좋았겠지만… 다른 차트를 그리다보니 (데이터를 입력하는 UX 와 어플리케이션의 UI는 둘째치고) 이 PantaRhei에는 2가지 결점이 있었다.

  1. 노드의 색상을 전부 하나로 밖에 할 수 없음
  2. 이미지를 그리는 방식이 Plot 기반이 아니라 Grid 기반 (이는 노드의 좌표를 입력 받는 다는 것에서도 알 수 있으며, 결과적으로 Shiny로 render할때 어마어마한 노가다를 필요로 했다. 심지어 창의 위치가 크기가 바뀌면 Grid 이미지가 깨짐)

그래서 눈물을 머금고 PantaRhei를 폐기…하고 ggsankeynetworkD3를 뒤적뒤적거렸다. 근데 생각보다 나쁘지 않았다(…?)

https://imgflip.com/memegenerator/205687331/Bird-Cracker 에서 만듬

networkd3는 이름에서도 알 수 있듯, D3.js를 기반으로 한 라이브러리보니 shiny와는 잘 맞았고, nodeedge도 커스텀 할 수 있었으며 여차하면 노드를 움직일 수 있다는 점도 괜찮았다. (라벨의 위치는 커스텀 안되는 것 같다)

물론 노드의 좌표를 미리지정할 수 없었고, (대신 자동으로 그려줌) 이동은 y축만 이동가능했기에 아래처럼 좀 이상한 그림이 나왔다.

Other income (1) 은 Operating profit (4) 위로 가야한다.

그치만 대충 js를 뜯어고쳐서 되게 했다. (이것도 뜯어고쳤다는 한 문장으로 표현되는 아쉬움…) 노드의 좌표를 지정하지 않아도 되어서 데이터 입력이 훨씬 간편해 진 것은 보너스

결과물 with networkd3

색상도 원래는 colourpicker로 올렸지만 material에서는 깨져서(…) ‘사용자가 언제 hex로 하겠어 몇개만 미리지정하자’ 라는 생각으로 타협해서 picker로 바꿨다.

배포 및 포장

(물론 아직 더 만들면 좋을 기능들이 많이 있긴 한데 일단 주요 기능인 차트 만드는 것은 잘 완성시켰으니…)

이 devarim (판타레이데바림이 나와야지) 은 사실 나 혼자 쓸꺼면 shiny 안씌우고 그냥 데이터 입력받아 차트 뱉는 함수로 만드는게 훨씬 낫다. 정말로

그러나 처음 의도, 재무는 알지만 코딩은 싫어하는 전문가한테 이 종목 재무 차트로 그려주셈 이라는 말을 할 수 있게끔 shiny를 뿌려 코드는 github에, 앱은 shinyapps 태워서 올렸다. hexstickerreadme도 예전에 만들었던 앱으로 만들어서 올림.

정리 + 노코드에 대한 생각

노코드를 정확하게 어떻게 정의하는 지는 모르겠지만 웹에서 마우스 80, 키보드 20으로 결과물을 만들 수 있으면 그게 노코드 가 되지 않을까? 고 생각했다.

이런 관점에서 노코드 툴을 만들고, 그 툴로 결과물을 만들어 봤으니 나도 노코드 개발자 ? 아님 말고 ㅋㅋ

  1. 이 노코드의 핵심은 “빠르게 시도”(성공하면 본격적으로 개발을 태우자) 인 것 같은데, 풀고자 하는 문제에 따라 노코드가 효과적인 부분이 있고 그렇지 않은 부분도 있는 것 같다.

그나마 경험이 많은 “데이터”라는 도메인을 예로 들어 생각해보면,

간단하고 가벼운 목적의 ‘대시보드’를 구현 할 수 있는 프로그램은 노코드의 활용이 나쁘지 않지만 빡센 딥러닝을 노코드로 구현한다? 좀 고민을 해봐야 하지 않을까 (물론 빅테크 형님들은 파이프라인도 노코드 서비스로 만들어주신다 ㅋㅋ)

2. 노코드 활용에는 결국 도메인이 중요한 것 같다.

조금 더 나아가면 이 생키 차트에만 해도 R이나 Shiny 보다는 재무 도메인이 더 필요한 것처럼 기술, 이나 뭔가를 해봤다라는 것에 매몰되지 않고 무엇을 왜 풀고자 하는 지를 고민하는 것이 더 중요할 것 같다. 근데 이런 생각을 트레이닝 하는 것보다 기술. 툴에 너무 집착하는 사람들이 많은 것은 걱정 (나도 포함 ㅎㅎ)

번외

  • 이 글은 외부 기고용이었지만. 아무리 짱구를 굴려도 이 글보다 글을 잘 풀어낼 자신이 없어서 그냥 버리고 개인 블로그에 썼음
  • (광고) 유사 노코드, Python 기반의 대시보드 제작툴로 Streamlit 강의를 만들 계획. (Python 기반이다 = 유료로 팔거다)
    커리큘럼 구성만 만들어놨고 이후는 아무것도 안함. 다만 12월 ~ 1월까지는 원주 문제가 있어서… 아마 1월 ~ 2월 연휴에 나올 듯. 관심 있으면 메일 주셈. 처음 몇명은 무료로 드림
  • 나는 R하고 Shiny를 할때 제일 빛나는 것 같다.
  • 미디엄에 코드블록이…? 개꿀

--

--

No responses yet