12  데이터 스토리텔링

지금까지의 실습 과정에서 우리는 보도에 적합한 데이터 분석 결과를 제시하는 방법으로 사회과학에서 사용하는 적절한 ‘조작화(operationalization)’와 ’시각화(visualization)’ 이라는 도구에 의지했습니다. 즉, 보도하고자 하는 내용을 추상적인 개념들과 개념들 간의 관계로 해석하고, 이를 다시 데이터에서 찾을 수 있는 측정치(measure)들로 바꾼 다음(조작화), 이를 보도 내용에서 상정하는 원인과 결과를 드러내는 데 적합한 시각 요소로 만들어 내는 연습을 해 왔다고 할 수 있습니다.

그런데, 여기까지의 작업은 어떻게 보면 데이터 저널리즘을 위한 ‘최소한’이라고 할 수 있습니다. 즉, 보도하고자 하는 내용에 따른 조작화와 시각화를 잘 수행하지 못한다면, 데이터 저널리즘 보도의 접근이 불가능하다고 볼 수 있지요. 그러면, 그 이상을 하려면 어떻게 해야 하는 것일까요? 보도 내용, 즉 전달하고자 하는 스토리와 데이터 저널리즘의 생산물, 즉, 시각화 결과가 얼마나 ’잘’ 연결되었는지에 대해서 고민해야 합니다. 다시 말해, 시각화 결과물이 보도 내용을 효율적으로 수용자에게 전달하는데 ‘효율적으로’ 기능하고 있는지를 평가해 보자는 것이지요. 이렇게 전달하고자 하는 정보의 언어적 차원, 즉, 스토리를 데이터에 대한 분석 결과물로 효율적으로 전달하는 것을 고민하는 영역을 ’데이터 스토리텔링’이라고 부릅니다.

이 장에서는 지금까지 배운 시각화 기술을 개선하여 데이터 스토리텔링을 잘 하는 법에 대해 배워 봅니다. 이는 물론 R을 이용해 그래프를 얼마나 더 보기 좋게 만들 것인가를 포함합니다. 그러나, 이는 단지 미적인 개선을 의미하는 것이 아닙니다. 우리가 여기서 배운 새로운 지식을 통해 만들게 될 그래프들은 전달하고자 하는 스토리를 잘 전달한다는 의미에서 더욱 보기 좋은 것일 것입니다. 물론 여러분들이 언론사에서 일하고 있는 기자라면, 데이터 스토리텔링 기법을 스스로 프로그램으로 구현할 필요가 없을지도 모릅니다. 그래픽을 담당하는 분들이 조직 내에 있는 경우도 많을테고, 이 분들이야말로 그래프를 시각적으로 훌륭하게 만드는데에는 전문가들일 테지요. 하지만, 데이터 스토리텔링은 그래프를 ‘예쁘게’ 만드는 것을 의미하지 않습니다. 기자가 언어로 전달하려는 ‘스토리’ 어떻게 시각 정보로도 구현할 것인가에 관한 이야기 이지요. 따라서, 데이터 저널리스트의 임무가 데이터를 통해 이야기를 전달하는 것이라면, 좋은 데이터 저널리스트는 이야기를 어떻게 시각적으로 전달할 것인가에 대한 아이디어도 가지고 있어야 합니다. 그렇기 때문에 여기서 이야기 하는 데이터 스토리텔링 기법들은 그래픽 전문가들과 소통, 협업을 하는 데에도 도움이 될 것입니다.

새로 배우게 될 R의 기능들에 앞서, 좋은 데이터 스토리텔링을 위해 가장 강조하고 싶은 도구는 바로 ‘정보의 위계(hierarchy)’ 입니다. 쉬운 말로 하면, 하나의 시각화 안에서도 더 중요한 정보와 덜 중요한 정보를 나누는 것입니다. 잘 생각해보면, 이는 스토리의 본질이기도 합니다. 우리는 앞서 데이터 저널리즘에서 보도의 내용을 개념과 개념 간의 관계로 모형화 했는데요, 바로 이 스토리의 중심이 되는 개념들과 그들의 관계 나타내는 시각 요소가 시각화 결과물의 ‘중요한’ 부분이라면, 그 외의 부분은 ‘중요하지 않은’ 부분이라고 할 수 있겠지요. 좋은 데이터 스토리텔링의 출발은 이렇게 중요한 시각화 요소와 중요하지 않은 시각화 요소를 구분한 다음 전자를 강조하고 후자를 단순화하거나, 과감하게 생략하는 것이라고 할 수 있습니다.

데이터 스토리텔링에서 정보의 위계가 중요한 것은, 정보 사이에 위계가 있어야만 독자들이 스토리의 중심이 되는 ‘더 중요한’ 정보에 주목하기 때문입니다. 물론, 수용자가 무한한 시각과 노력을 들여 내 기사를 읽어 줄 준비가 되어 있다면, 이런 걱정은 할 필요가 없을 것입니다. 하지만, 여러분이 기자로서, 또 심지어 독자로서 더 잘 알고 있듯이, 뉴스를 마주한 독자는 결코 그 뉴스에 시간과 노력을 다 하려 하지 않습니다. 어떻게 생각하면, 공들여 쓴 기사로부터 달아날 핑계를 최선을 다 해 찾고 있는 것처럼 느껴지기도 하지요. 심지어, 그 기사를 읽겠다고 본인이 기사를 열었는데도 말이지요! 따라서, 우리는 독자들의 한정된 인지자원(cognitive resource)에 대해 늘 생각하야 합니다. 그리고 그들이 아주아주 한정된 시간과 에너지를 가지고도 기사와 데이터로 찾은 증거들을 이해하고 받아들일 수 있도록 고심해야 하는 것이지요. 따라서, 데이터 스토리텔링을 잘 하기 위해서는 일종의 인간의 ’영상심리’에 대한 기초적인 이해가 필요합니다.

12.1 인간의 세 가지 기억 시스템과 뉴스

`영상심리’라고 해서 무언가 대단한 이론을 이야기하고자 하는 것은 아닙니다. 여기서 이야기 할 것은 우리가 이미 상식으로, 또는 경험에서 알고 있는 것들을 확인하는 것이라고 보아도 무방합니다.

앞서 이야기 한 것처럼, 사람은 새로 접한 정보를 처리하는데 대단히 한정적인 자원을 가지고 있습니다. 대신, 한정된 자원을 나름대로 효율적으로 활용하기 위한 방안도 마련하고 있다고 합니다. 그 중 하나가, 여러 단계의 기억 시스템 입니다. 심리학자들은 인간이 시각을 통해 받아들이고 기억하는 방식이 하나가 아니라 여러개라고 합니다. 이를 구분하는 방법 중 하나가 영상기억(iconic memory)-단기기억(short-term memory)-장기기억(long-term memory)의 3단계 구분법 입니다. 각각의 기억 방식은 인간의 시각정보 처리 과정에서 다른 기능을 하며, 하나의 정보에 대해 동시에 작동하기도, 그렇지 않기도 합니다.

영상기억, 단기기억, 장기기억

영상기억은 ‘기억’이라는 용어와 어울리지 않게, 1초 또는 그 이하의 짧은 시간 동안 작동하는 기억 시스템입니다. 이는 빠르게 시각 정보의 개략적인 내용을 파악하고 거르기 위한 영상 정보의 ’입력’ 방식이라고 할 수도 있습니다. 어떤 사람들은 이런 영상기억이 진화의 산물이라고 하는데, 예컨대 야생 상황에서 천적이나 먹잇감을 빠르게 알아차리고 대응하기 위해 기능하는 영상 정보 처리 방식이라는 것입니다. 이를 시각화 과정에 결부시켜 보면, 독자가 대략적으로 정보를 훑는 와중에 ‘시선을 끄는’ 요소에 주목하게 되는 과정이라고 볼 수 있습니다. 영상기억이 작동하는 데에는 전주의적속성(preattentive attributes)이라는 우리 뇌 속에 미리 장착되어 있는 틀이 작동한다고 합니다. 이러한 틀들은 우리가 주의를 기울이지 않아도(‘전주의적’) 순식간에 알아차릴 수 있 수 있는 시각 요소들입니다.

전주의적 속성에는 방향, 길이, 너비, 크기, 형태, 곡률, 표시추가, 둘러싸기, 색상, 색조, 위치 공간적 그룹핑 등이 있습니다. 우리는 이를 이용해서 독자가 바로 알아차리고 주목했으면 하는 영상 정보를 강조할 수 있는 것이지요. 즉, 주목을 원하는 정보를 강조하기 위해 전주의적 속성을 이용할 수 있습니다.

전주의적 속성

단기기억은 영상기억보다는 길지만 초 단위에 해당하는 아주 짧은 기억 방식 입니다. 말하자면, 여러분이 새로운 전화번호를 듣고 머릿속에 기억했다가 금방 잊어버리는 경우가 있지요? 그 때 사용하는 기억 방식을 단기기억이라고 보아도 좋습니다. 뉴스의 경우를 생각해 보면, 독자가 시각 정보를 보면서, 관련된 글을 읽을 때 중간중간 사용하게 되는 정도의 기억 방식 입니다. 글을 읽다가, 관련 그래프를 보고 해당 정보를 이해한 뒤 다시 글로 돌아와야 하는 경우가 있지요? 아마 그 과정은 30초 이내가 될 것입니다. 그 때 사용되는 기억 능력은 기껏해야 우리가 전화 번호를 외울 때 사용하는 그다지도 불완전한 능력에 불과하다는 것이지요. 단기 기억을 이용할 때 인간이 기억할 수 있는 영상 정보는 흔히 기껐해야 3-5개의 아이템 정도라고 합니다. 따라서, 독자가 보도 내용과 시각화 결과를 잘 연결하기를 바란다면(즉, 스토리텔링을 잘 하길 바란다면), 3-5개 이상의 시각 요소가 한 번에 담긴 화려한 시각화를 이용해서는 안 되겠지요. 따라서, 중요한 정보와 중요하지 않은 정보를 가려내고(즉, 정보의 위계를 잘 파악하고), 중요하지 않은 정보를 과감하게 생략하는 것이 중요합니다.

장기기억은 훨씬 더 큰 용량을 가지고 오랫 동안 지속되는 기억 입니다. 문제는 단기 기억에 포함되었던 모든 정보가 장기 기억으로 전달되지 않는다는 것입니다. 어떤 심리학자들은 이렇게 단기기억이 장기기억으로 넘어가는 과정에서 일종의 인코딩이 일어난다고 합니다. 즉, 원정보를 그대로 기억하는 것이 아니라, 장기기억에 적합한 방식으로 변형한 다음에야 저장할 수 있다는 것이지요. 그렇게 장기 기억에 도움을 주는 인코딩 방식으로 흔히 이야기 하는 것이 바로 ‘이야기(story)’ 입니다. 즉, 논리적으로 구성된 정보의 체계는 인간이 오래 기억하기 어렵지만, 인간의 언어로 다시 되풀이된, 심지어 기승전결을 가진 이야기는 훨씬 더 기억하기 좋다는 것입니다. 예전에 방송에서 김영하 작가가 “이야기는 인간의 기억을 위해 만든 도구이다”라는 말을 한 적이 있는데 같은 맥락이라고 할 수 있겠네요.

시각화를 위해 이것이 의미하는 바는 여러분이 시각화 자료를 최종적으로 완성함에 앞서 전달하고 싶은 이야기가 명료해야 한다는 것입니다. 여기서 명료하다는 것은 논리적이라는 의미라기 보다는 단순하고 직관적이어야 한다는 것입니다. 이를 위해 많은 전문가들은 시각화 또는 기사 작성에 앞서 전달하고 싶은 이야기를 하나의 문장으로 표현할 것을 권합니다. 이는 막상 해 보면 대단히 어려운 작업이기도 하고, 한 번에 달성하기 어려운 작업 이기도 합니다. 대부분의 경우, 전달하고 싶은 이야기를 한 문단으로, 그것을 다시 두 세 문장으로, 그런 다음 하나의 문장으로 줄이는 순차적인 과정을 필요로 하지요. 그런 다음 여러분의 시각화 자료로 돌아가서 다시 물어보야 합니다. 나의 시각화 결과물은 그 한 문장을 전달하고 있는가? 그 한 문장과 관련이 없는 필요 없는 정보를 지나치게 많이 전달하려고 있지 않은가?

12.2 정보 생략과 게슈탈트 심리학

지금까지 이야기한 데이터 스토리텔링의 원리를 한 마디로 요약하자면, 가장 중요한 정보를 제외한 부수적인 정보는 가능한 한 빼라는 것입니다. 독자의 집중력을 고려하면, 초점을 맞추어야 하는 것은 중요한 정보를 강조하는 것보다 중요하지 않은 정보를 빼는 것이라고 할 수도 있겠습니다.

그런데 위의 예에서도 주요 메시지를 전달하는 시각 요소가 아니더라도, 완전히 생략할 수 없는 정보들이 있습니다. 예컨대 그래프의 X축과 Y축의 단위나 눈금 같은 것들이 그렇지요. 이런 시각 요소들은 놀랍게도 여전히 독자의 인지자원을 소비하기 때문에, 생략을 할 수 있다면 생략하는 것이 좋습니다. 그러나 너무 많은 생략은 독자들로 하여금 그래프를 이해할 수 없도록 만들 수도 있겠지요.

그렇다면 얼마나 많은 정보를 생략해도 되는 것일까요? 이에 대한 정답은 없지만, 실제로 결정하는데 있어 가이드라인으로 자주 인용이 되는 게슈탈트(Gestalt) 심리학 이라는 이론이 있습니다. 게슈탈트 심리학은 현대에 발전한 많은 심리학 이론들이 그런 것처럼 인간 심리나 뇌 기능의 부분 부분에 주목하기 보다는 그러한 부분들이루는 조합 또는 구조가 인지를 가능하게 한다고 보는 하나의 사조라고 볼 수 있습니다. 하지만 UI/UX 디자인에서 이야기 하는 게슈탈트 심리학에서 발달한 영상심리학 관련 특정 결과들에 주목하는데요, 특히 게슈탈트 심리학이 이야기 하는 여러 심리 원리 중에 인지적 원리로서 창발성(emergence) 또는 구상화(Reification)가 중요합니다. 창발성 또는 구상화는 인간이 감각 기관, 예컨대 시각을 통해 감각한 정보 이외/이상의 것을 인지할 수 있는 것을 의미합니다. 즉, 직접적으로 보여주지 않아도 알게되는 것들이 있다는 것이지요.

예컨대 이를 설명하는 여러 법칙 중에 ‘근접성의 법칙(Law of Proximity)’ 이라는 것이 있습니다. 아래의 예에서 자연스럽게 우리는 가로로 배열되어 있는 원들이 아니라 새로로 배열되어 있는 원들 사이에 어떤 가까운 관계가 있다고 여기게 됩니다. 이 그림은 관계를 시각 정보를 통해 직접적으로 표현하지 않았지만 우리는 근접성의 원리를 통해 자연스럽게 이를 인지하는 것이지요. 그렇다면, 그 관계를 설명하기 위해 일부로 세로줄을 그어서 관계를 표현해줄 필요가 없습니다. 독자는 그것 없이도 관계를 인지할 수 있는 데다가, 그러한 부가적인 시각 요소는 독자가 가진 한정적인 인지자원을 소모하게 만들기 때문입니다.

https://kimhaksung.tistory.com/entry/gestalt

유사하게 ‘유사성의 법칙(Law of Similarity)’, ‘연속성의 법칙(Law of Continuity)’ 같은 것들도 있습니다. 즉, 모양이 비슷한 것, 연속적으로 이어져 있는 것을 통해 인간의 관계를 자연스럽게 인식한다는 것입니다.

유사성과 연속성

‘폐쇄성의 법칙(Law of Closure)’ 같은 것도 흥미롭습니다. 아래의 예를 보면, 사람은 삼각형이 명확하게 그려져 있지 않아도 이중 삼각형 구조를 이해할 수 있습니다. 인간의 뇌가 완성되어 있지 않은 폐쇄 구조를 알아서 완성하기 때문이지요.

폐쇄성

이러한 게슈탈트 법칙을 어떤 사람들의 ‘형상 인지의 경제 법칙’이라고 표현하기도 합니다. 즉, 인간이 한정된 인지 자원과 정보를 가지고도 ’효율적으로’, 많은 인지자원을 쓰지 않고 형상을 인지할 수 있게 해 주는 시스템 같은 것을 가지고 있다는 이야기지요. 그렇다면, 우리는 인간이 자연스럽게 받아 들일 수 있는 형상의 인지 능력을 어느 정도 믿고, 그러한 능력을 보완해주기 위한 부가 정보는 과감하게 생략해도 좋겠지요. 이제 시각화에서 그러한 예를 한 번 보도록 하겠습니다.

생략 작업 전의 그래프 아주 익숙한 예이지요? 여러분들이 마이크로소프트 엑셀 등을 이용해서 그래프를 생성하면 기본적으로 얻을 수 있는 모양의 그래프 입니다. 전달해야 할 모든 거의 모든 정보를 충실하게 전달하고 있는 이 그래프의 문제점은 무엇일까요? 아마도 예상하실테지만, 독자로 하여금 지나치게 많은 정보를 처리할 것을 요구하고 있다는 것입니다. 그렇다면, 어떤 정보가 ‘과도한’ 정보일까요? 가장 직관적으로는 추가적인 정보를 전달하지 않는 중복된 시각화 요소들을 지울 수 있습니다. 예컨대, 날짜를 표시할 때 반복되는 연도표시는 생략해도 좋습니다. 중요하지 않아보이지만, 독자는 이런 사소한 정보를 처리하기 위해서도 두뇌의 자원을 소비합니다. 또, 같은 이유로 세로축에 표시된 숫자의 소숫점 역시 생략해도 좋겠지요. `.0’은 아무런 정보도 전달하지 않으니까요. 그래프와 그래프 상단의 텍스트를 구분하는 두꺼운 선 역시 필요하지 않습니다. 앞서 언급한 ’폐쇄성의 원칙’에 따라 독자들은 텍스트 부분과 그래프 부분을 적절하게 구분할 수 있기 때문에 그러한 구분선은 아까운 독자들으 집중력을 분산시키는 방해 요소에 불과합니다. 그러면 이렇게 최소한의 생략 작업만을 거친 그래프를 살펴볼까요?

최소한의 생략 작업 이러한 생략 작업만으로도 가독성이 훨씬 높은 그래프라는 것이 한눈에 보이지요?

이 이상 어떤 것들을 생략할 수 있을까요? 여기서부터는 여러분이 전달하고자 하는 ’이야기’에 따라 정해집니다. 이것이 중요합니다. 일반적으로 중요하지 않은 정보라는 것은 사실 없습니다. 전달하고자 하는 스토리를 고려했을 때 상대적으로 중요하지 않은 정보가 있는 것이지요.

스토리에 대해 이야기하기 전에 이 그래프가 전달하고 있는 정보에 대해서 조금 더 이해해 보도록 합시다. 첫째, 이 그래프는 어떤 회사가 판매 계약을 채결하는데 걸리는 시간을 월별로 시각화 해 주고 있습니다. 그런데 판매는 직접 판매(초록색 막대)와 간접 판매(파란색 막대)로 구분되고, 각각 계약 체결에 걸리는 시간이 다르다는 것을 알 수 있네요. 또 하나 알 수 있는 것은 회사에 달성하고자 하는 목표가 있다는 것입니다. 위에 90일이 목표라고 쓰여 있지요? 다시 그래프로 돌아가 보니, 어떤 경우에는 계약 체결에 90일이 걸리지 않아 목표를 달성한 경우도 있고, 90일을 초과해서 목표를 달성하지 못한 경우도 있네요.

이제 전달하고 싶은 주된 이야기를 가정해 봅시다. 예컨대, 직접 판매와 간접 판매의 계약 체결 기간이 비슷할 때도 있지만 상당히 차이가 나는 경우가 있지요? 이 차이가 주로 전달하고 싶은 이야기라고 해 보지요. 이제 전달하고 싶은 이야기가 결정되었으니, 그 이야기를 전달하는데 필요한 시각 정보 이외의 것들은 가능한 생략하는 것이 좋겠네요. 에컨대, 직접 판매와 간접 판매 사이의 ’차이’를 보이는 것이 스토리라면 각 판매방식의 계약 체결 기간을 표시할 필요성은 떨어집니다. 따라서 바 그래프 위의 숫자는 지워도 좋아 보입니다. 또, 막대 그래프는 차이를 보이기 위해서는 불필요한 시각 정보를 너무 많이 사용하는 방식의 그래프 입니다. 결국 중요한 것은 막대의 높이, 그리고 그 높이의 차이인데, 막대 그래프는 그것을 사각형의 꽉찬 도형으로 보여주고 있거든요. 이 역시 독자의 인지자원을 불필요하게 소비하는 요소입니다. 그런데, 가로축은 ’시간’이기 때문에, ’연속성의 원칙’에 따른 선그래프로 정보를 표현했을 때, 사람들은 자연스럽게 그래프를 좌에서 우로, 시간의 흐름에 따라 이해할 수 있습니다. 다음과 같이 말이죠.

선그래프 이렇게 그래프 종류만 바꾸었는데도 여러가지 개선이 이루어졌습니다. 첫째, 높이 정보를 표현하는데 필요한 것 이외의 시각정보가 사라져 그래프를 읽기 쉬워졌습니다. 둘째, 불필요한 시각 정보가 사라지면서 두 선 사이의 차이에 더욱 주목할 수 있게 되었습니다. 셋째, 선 그래프를 통해 시간의 흐름에 따라 차이도 변화한다는 것을 쉽게 이해할 수 있게 되었습니다.

만약, 전달하고자 하는 스토리가 단지 두 판매 방식의 차이보다는 간접 판매 방식이 간혹 목표치를 초과한다는 것이라고 해 볼까요? 그렇다면 정보의 위계에서 목표치에 해당하는 90일이 부수적인 시각요소로 표현되기 보다는 독자가 가장 먼저 주목하는 그래프 상에 함께 표현되는 것이 좋겠지요. 다음 그래프를 보시죠.

선그래프와 목표치 이제 (직접 판매가 아닌) 간접 판매가 경우에 따라 목표치를 종종 초과한다는 것이 명확해졌습니다. 다시 반복하지만, 여기서 중요한 것은 전달하고 싶은 주된 스토리에 따라 정보의 위계가 바뀌었고, 그에 따라 정보의 표현 방식이 바뀌었다는 것입니다.

생략이 잘 이루어졌다면, 전주의적 속성을 이용한 강조를 고려해볼 수 있습니다. 여기서는 스토리에 따른 정보의 위계를 따지는 것이 더욱 중요합니다. 예컨대, 위의 예에서 간접 판매가 목표치를 초과하는 몇몇 사례들에 주목하고 싶다고 해 볼까요? 그렇다면, 과감하게 텍스트에 핵심 메시지를 전달함과 동시에, 그에 해당하는 시각 정보를 바로 강조하는 방식을 고려해볼 수 있습니다. 아래의 예를 보시죠.

색상을 이용한 강조

텍스트로 전달하고자 하는 메시지가 표현이 되었고, 해당 텍스트와 같은 색상을 선 그래프에서 목표치 초과 사례와 매칭 시켜, 해당 메시지를 이해하기 위해서는 그래프의 어느 부분에 주목해야 하는지를 지시해 주었습니다. 독자들이 같은 색상을 통해 자연스럽게 두 시각 정보를 연결할 것을 기대하는 것이지요. 대신 상대적으로 덜 중요한 목표치나 직접 판매액, 그리고 나머지 눈금 등은 회색으로 색상을 변경하여 정보의 위계를 분영히 했습니다.

하지만, 전달하고 싶은 스토리가 같은 정보의 긍정적인 면, 즉, 위에서 강조한 세 번을 제외하고는 대부분의 경우 목표치를 달성했다는 것이라면, 오히려 직접 판매에 해당하는 그래프는 중요정보에 해당하므로, 회색으로 처리하기 보다는 눈에 띄는 색상으로 전달하는 것이 바람직하겠지요.

색상을 이용한 강조의 다른 예

12.3 ggplot2를 이용한 데이터 스토리텔링 기초

이 장에서 이야기한 데이터 스토리텔링 기법들을 앞서 배운 데이터 시각화 과정에 도입하려고 생각해 보면, 결국 ggplot2를 이용한 코드에 어떤 조작을 가해 그래프를 변형해야 한다는 것을 알 수 있습니다. ggplot2가 선풍적인 인기를 얻게 된 데에는 바로 출판할 수 있는 양질의 시각화를 프로그래밍을 통해 할 수 있다는 사실과 함께, 프로그래밍으로 가능한 최대한의 유연성을 제공한다는 이유도 있습니다. 이러한 유연성 덕분에 지금까지 이야기한 모든 스토리텔링 기법들은 ggplot2로 구현 가능합니다.

단, 여기서 간단하게 언급할 ggplot2의 확장 기능들은 모든 스토리텔링 기법들을 구현할 수 있을 정도의 심화된 내용은 아닙니다. 조금 더 발전된 내용은 다소 복잡하기에 별도의 챕터에서 따로 설명하려고 합니다. 만약 여러분들이 스스로 그래픽 까지 만들어야 하는 기자라면 해당 장 역시 공부하시기를 권합니다. 반면, 여러분이 그래프 제작을 다른 누군가에게 맡길 수 있다고 하더라도, 이 챕터의 나머지 부분에서 언급하는 내용은 숙지하시는 것을 권합니다. 왜냐하면 여러분들이 지금까지 만들어낸 최소한의 시각화 결과물은 독자 뿐 아니라, 여러분의 시각화를 담당하는 파트너가 이해하기에도 난해할 가능성이 크기 때문이지요. 즉, 여기서 이 장에서 이야기 하는 ggplot2의 확장 기능은 독자 보다는 여러분들의 동료와 소통을 하기 위한 최소한의 시각화 개선 도구라고 생각하시면 되겠습니다.

그러면 먼저, 지금까지 만든 시각화 결과물은 타인이 함께 일하는 동료도 이해하기 힘들 것이라는데 대한 이야기부터 해 볼까요? 다음은 시각화에 관한 장에서 donorschoose.org 데이터를 이용해 미국 하와이주(HI)와 뉴욕주(NY)의 연도별 평균 프로젝트 목표액 추이를 표현하는데 이용한 것과 동일한 코드입니다.

library(tidyverse)
library(lubridate)
options(scipen=999)
Sys.setlocale("LC_ALL","Korean")
[1] "LC_COLLATE=Korean_Korea.949;LC_CTYPE=Korean_Korea.949;LC_MONETARY=Korean_Korea.949;LC_NUMERIC=C;LC_TIME=Korean_Korea.949"
projects <- read_csv("data/projects.csv")
projects |> 
    mutate(year = year(date_posted)) |>
    group_by(school_state, year) |>
    summarise(avg_size = mean(total_price_excluding_optional_support)) |> 
    filter(school_state %in% c("HI", "NY")) |>
    ggplot() +
    aes(x=year, y=avg_size, color=school_state) +
    geom_line() +
    geom_point()
`summarise()` has grouped output by 'school_state'. You can override using the
`.groups` argument.

이 그래프를 당장 시각화 담당자에게 전달하면 어떤 반응을 얻을까요? 제 예상에는 “avg_size가 뭐에요?”라고 할 것 같습니다. 우리는 코드를 직접 작성했으니 avg_size에서 “avg”가 평균이라는 것도 자명할테고, 그것이 프로젝트 목표액의 평균이라는 것도 분명하겠지만, 시각화 담당자는 그렇지 않겠지요. 이 때는 그래프의 avg_size라는 변수명 대신 y축의 이름(ggplot에서는 y축의 ’타이틀’이라고 합니다)만 바꾸어 주어도 오해의 소지가 줄어들 것입니다.

ggplot2의 좋은 점 중 하나는 이렇게 그래프의 세부사항을 수정하는 작업 역시 지금까지 해왔던 것과 같이 계층(layer)을 쌓는 방식으로 일관되게 할 수 있다는 점입니다. 에를들어 그래프 타이틀 변경은 labs()라는 함수를 새로운 계층으로 변경해서 수행합니다.

projects |> 
    mutate(year = year(date_posted)) |>
    group_by(school_state, year) |>
    summarise(avg_size = mean(total_price_excluding_optional_support)) |> 
    filter(school_state %in% c("HI", "NY")) |>
    ggplot() +
    aes(x=year, y=avg_size, color=school_state) +
    geom_line() +
    geom_point() +
    labs(x="연도", y="평균 목표액", color="주(State)")

앞의 그래프에서 마지막 줄의 labs(x="연도", y="평균 목표액", color="주(State)")+ 기호를 통해 더해졌다는 점에 주목해주세요. 그래프 세부사항의 수정 역시 계층(layer)을 더해 할 수 있다는 것은 바로 이러한 방식을 의미합니다. 기존의 그래프를 생산하는 코드는 수정할 필요가 없는 것이지요. 그래서, 혼자 빠르게 시각화 결과를 확인해보고 싶을 때에는 그래프 작업을 위한 최소한의 골조만을 작성하고, 다른 사람과 협업할 필요가 있을 때에는 그래프를 수정하기 위한 계층을 몇 줄 덧대는 방식으로 그래프를 수정해서, 업무를 효율화할 수 있습니다.

그 외의 다른 옵션을 추가한 그래프도 볼까요?

projects |> 
    mutate(year = year(date_posted)) |>
    group_by(school_state, year) |>
    summarise(avg_size = mean(total_price_excluding_optional_support)) |> 
    filter(school_state %in% c("HI", "NY")) |>
    ggplot() +
    aes(x=year, y=avg_size, color=school_state) +
    geom_line() +
    geom_point() +
    labs(x="연도", y="평균 목표액", color="주(State)") +
    scale_x_continuous(breaks=2002:2014, labels=2002:2014) + 
    scale_y_continuous(breaks=seq(400, 1800, by=200), labels=seq(400, 1800, by=200)) +
    scale_color_discrete(labels=c("하와이", "뉴욕")) +
    theme(panel.background = element_rect(fill = "white"),
          panel.grid.major = element_line(size = 0.5, linetype = 'dashed',
                                colour = "grey"), 
          panel.grid.minor = element_line(size = 0.25, linetype = 'dotted',
                                colour = "lightgrey"))

특별히 더 나은 그래프는 아닌 것 갓지만 여기서 보아야 할 것은 이렇게 추가적인 수정을 하는데에는 추가적인 계층을 덧붙이는 것으로 충분하는 것입니다. 위의 코드를 조금 더 자세히 살펴보면 다음과 같습니다.

  • scale_x_continuous(breaks=2002:2014, labels=2002:2014)
    • 연속변수(contiuous)인 x축(연도)의 눈금 표현을 2002, 2003, …, 2014 각각에 대응해서(breaks), 동일한 숫자로 표현(labels)해 줄 것 (이전의 그래프에는 2005와 2010만 표시되었지요.)
  • scale_y_continuous(breaks=seq(400, 1800, by=200), labels=seq(400, 1800, by=200))
    • 연속변수(contiuous)인 y축(평균 목표액)의 눈금 표현을 400, 600, …, 1800 값에 대응해서(brakes), 동일한 숫자로 표현(labels)해 줄것 (이전의 그래프에서는 간격이 200이 아닌 400이었습니다).
  • scale_color_discrete(labels=c("하와이", "뉴욕"))
    • 이산변수(discrete)인 color(주)의 변수값을 원래의 HI, NY 대신 “하와이”, “뉴욕”으로 표현해 줄 것.
  • theme(panel.background = element_rect(fill = "white"))
    • 그래프 패널의 배경(panel.background)를 하얀색으로 채워진(fill="white") 사각형 요소(element_rect())로 채울 것.
  • theme(panel.grid.major = element_line(size = 0.5, linetype = 'dashed', colour = "grey"))
    • 그래프의 주눈금선(panel.grid.major)를 두께가 0.5인 회색 대쉬 선 요소(element_line())으로 변경할 것.
  • theme(panel.grid.minor = element_line(size = 0.25, linetype = 'dotted', colour = "lightgrey"))
    • 그래프의 부눈금선(panel.grid.minor)를 두께가 0.5인 옅은회식 점선 요소(element_line())으로 변경할 것.

이미 약간 복잡하지요? ggplot2에는 이밖에도 그래프 수정을 위한 많은 함수들을 갖추고 있기 때문에 여기서 모든 기능을 설명할 수는 없습니다. 이를 모두 머리속에 기억하고 있다가 코딩할 때 꺼내 쓰는 사람도 별로 없지요. 다만 다음과 같은 원칙 정도를 기억하시면, 필요한 코드를 찾아 쓰는데 도움이 될 것입니다.

  • labs() 계층: 그래프에 표현되는 변수들의 이름을 바꾸어 줌.
  • scale_..._...() 계층: ggplot2 내부 변수(x, y, color, fill 등)가 그래프로 표현되는 방식을 바꾸어 줌. 단, 함수명은 때에 따라 바뀜. scale_..._...()에서 첫번째 ...에는 내부 변수명이, 두번째 ...에는 해당 변수의 타입이 들어감. 즉, scale_x_contiuous()는 연속형은 x변수의 그래프 표현을 바꾸어주기 위한 계층을 생성하는 함수.
  • theme() 계층: 내부 변수의 표현과 무관한 그 외 미적 요소를 변경하는 역할을 함.

한 가지만 더 첨언하자면, theme()을 어떻게 수정할 것인지 고민할 필요 없이 ggplot2가 미리 제공하는 테마 중 하나를 그냥 선택해도 좋습니다. 다음과 같이 말이죠.

projects |> 
    mutate(year = year(date_posted)) |>
    group_by(school_state, year) |>
    summarise(avg_size = mean(total_price_excluding_optional_support)) |> 
    filter(school_state %in% c("HI", "NY")) |>
    ggplot() +
    aes(x=year, y=avg_size, color=school_state) +
    geom_line() +
    geom_point() +
    labs(x="연도", y="평균 목표액", color="주(State)") +
    scale_x_continuous(breaks=2002:2014, labels=2002:2014) + 
    scale_y_continuous(breaks=seq(400, 1800, by=200), labels=seq(400, 1800, by=200)) +
    scale_color_discrete(labels=c("하와이", "뉴욕")) +
    theme_classic()

위 그래프에서는 복잡한 theme() 옵션이 theme_classic()이라는 단순한 옵션으로 바뀌었지요? 이는 ggplot2가 기본적으로 제공하는 테미입니다. 그 외에도 theme_bw(), theme_minimal() 여러가지가 존재합니다. 더 자세한 사항은 한국생명공학연구원 김하성 박사의 강의자료를 참조해 보시기를 권합니다.

마지막으로 한 가지 더 재미있는 수정을 해 보겠습니다. 앞서 ggplot2가 theme_classic(), theme_bw() 등의 몇 가지 기본 테마를 제공한다고 했지요? 이러한 기본 테마를 추가해주는 패키지도 존재합니다. 다음과 같이 새로운 패키지를 설치해 보세요.

install.packages("ggthemes")

설치가 되었으면 해당 패키지를 불러준 다음 다음과 같이 코드 마지막 줄을 수정해 줍니다.

library(ggthemes)
projects |> 
    mutate(year = year(date_posted)) |>
    group_by(school_state, year) |>
    summarise(avg_size = mean(total_price_excluding_optional_support)) |> 
    filter(school_state %in% c("HI", "NY")) |>
    ggplot() +
    aes(x=year, y=avg_size, color=school_state) +
    geom_line() +
    geom_point() +
    labs(x="연도", y="평균 목표액", color="주(State)") +
    scale_x_continuous(breaks=2002:2014, labels=2002:2014) + 
    scale_colour_economist(labels=c("하와이", "뉴욕")) +
    theme_economist() +
    ggtitle("donorschoose.org 연도별 평균 목표액")

한글이 섞여있어 익숙하게 보일지 모르겠습니다만, 이 테마는 영국의 유명한 주간지 가 사용하는 테마입니다. 유사하게 theme_wsj(), scale_colour_wsj() 함수를 이용해 <월스트리트저널>의 테마를 이용하는 것도 가능합니다.