聰明不如鈍筆
총명불여둔필
assignment KindeR

ggplot2 그래프 색깔 마음대로 바꾸기(feat. scale_*_manual)


R 조금 더 정확하게는 ggplot2 패키지로 그래프를 그리다 보면 마음에 드는 색깔을 골라서 항목을 칠하고 그 색깔을 계속 유지하고 싶을 때가 있습니다.


예컨대 요일별 데이터를 다룰 일이 있다면 토요일은 파랑, 일요일은 빨강으로 고정하면 직관적으로 이해하는 데 도움을 받을 수 있을 겁니다.


이번 포스트에서는 프로야구 각 팀 대표색으로 그래프를 칠하고 그 색깔을 계속 유지하는 연습을 해보겠습니다.


이 포스트를 통해 이 블로그를 처음 찾은 분께 말씀드리면 프로야구 데이터를 활용해 연습하는 게 이 블로그 전통(?)입니다.


자, 그럼 이제 본격적으로 시작해 보겠습니다.


늘 그렇듯 제일 먼저 할 일은 물론 tidyverse 패키지 (설치하고) 불러오기.

#install.packages('tidyverse')
library('tidyverse')
## -- Attaching packages ------------------------- tidyverse 1.3.0 --
## √ ggplot2 3.3.0     √ purrr   0.3.4
## √ tibble  3.0.1     √ dplyr   0.8.5
## √ tidyr   1.1.0     √ stringr 1.4.0
## √ readr   1.3.1     √ forcats 0.5.0
## -- Conflicts ---------------------------- tidyverse_conflicts() --
## x dplyr::filter() masks stats::filter()
## x dplyr::lag()    masks stats::lag()


이어서 지난해(2019년) 각 구단 팀 OPS(출루율+장타력)로 데이터 프레임을 만들어 ops라는 변수에 넣어놓겠습니다.

tribble(
  ~팀, ~ops,
  '키움', .768,
  'NC', .762,
  '두산', .745,
  'KT', .729,
  '삼성', .718,
  'SK', .718,
  'LG', .711,
  'KIA', .706,
  '한화', .686,
  '롯데', .674
) -> ops


물론 잘 들어갔겠지만 혹시 모르니 확인 전화를 한 통 넣어봅니다.

ops
## # A tibble: 10 x 2
##    팀      ops
##    <chr> <dbl>
##  1 키움  0.768
##  2 NC    0.762
##  3 두산  0.745
##  4 KT    0.729
##  5 삼성  0.718
##  6 SK    0.718
##  7 LG    0.711
##  8 KIA   0.706
##  9 한화  0.686
## 10 롯데  0.674


이제 팀별 OPS 막대 그래프를 그려봅니다. 팀별로 막대 색깔을 달리하겠습니다.

ggplot(data=ops, aes(x=팀, y=ops, fill=팀)) +
  geom_bar(stat='identity')


다들 잘 아시는 것처럼 따로 색을 지정하지 않으면 ggplot2는 이렇게 내장 기본 팔레트에 따라 색깔을 선택합니다.


이 포스트를 찾아오신 분이라면 ggplot2 기본 문법은 알고 계실 거라고 믿습니다.


그래도 혹시 저 위에 있는 코드가 무슨 뜻인지 모르겠다고 생각하시는 분이 계시면 '최대한 친절하게 쓴 R로 그래프 그리기(feat. ggplot2)' 포스트가 도움이 될 수 있습니다.


이제 색을 바꿔 보겠습니다.


ggplot에서 따로 원하는 색을 지정하고 싶을 때는 scale_fill_manual() 함수를 쓰시면 됩니다.


이번에는 그래프 속을 칠하는(fill) 연습이라 scale_fill_manual()입니다.


만약 color 속성을 바꾸고 싶으실 때는 scale_color_manual()을 쓰시면 됩니다.


아이유 '팔레트' 뮤직 비디오 중에서. 유튜브 캡처


이 함수는 'scale_color_manual(values=팔레트)' 형태로 씁니다.


팔레트를 만들려면 색이 여러 개 필요하겠죠?


우리가 원하는 프로야구 각 팀 대표 색은 이 위키피디아 틀에서 확인할 수 있습니다.


색깔을 확보했으면 팔레트 자체를 만드는 방법은 간단합니다.


'항목 이름'='색깔' 형태로 그냥 주욱 이어 붙이기만 하면 되거든요.

c('두산'='#131230',
   '롯데'='#002955',
   '삼성'='#074ca1',
   '키움'='#7c0022',
   '한화'='#ff6600',
   'KIA'='#c70125',
   'KT'='#000000',
   'LG'='#c30452',
   'NC'='#315288',
   'SK'='#ff0000') -> kbo_palette


이번에도 잘 들어갔는지 안부 전화 한통.

kbo_palette
##      두산      롯데      삼성      키움      한화       KIA        KT        LG 
## "#131230" "#002955" "#074ca1" "#7c0022" "#ff6600" "#c70125" "#000000" "#c30452" 
##        NC        SK 
## "#315288" "#ff0000"


그냥 '짝 맞추기'를 한 거니까 이 팔레트 자체는 사실 특이할 게 없습니다.


아, 역시나 혹시 모르시는 분이 계실까 봐 말씀드리면 여기 나온 이상한 숫자+문자 조합은 '웹 색상'이라는 녀석입니다.


문자 그대로 웹 사이트를 만들 때 색깔을 쓰는 방식으로 16진법 숫자 3개를 조합한 겁니다.


이 링크를 클릭하시면 원하는 색깔을 이 형태로 어떻게 표현하는지 확인하실 수 있습니다.


위에서 'scale_fill_manual(values=팔레트)' 형태로 쓴다고 했으니까 우리가 원하는 코드는 'scale_fill_manual(values=kbo_palette)'가 될 겁니다.


위에서 쓴 코드에 이 한 줄을 붙여 보겠습니다.

ggplot(data=ops, aes(x=팀, y=ops, fill=팀)) +
  geom_bar(stat='identity') +
  scale_fill_manual(values=kbo_palette)


어쩐지 못 생긴 느낌적인 느낌이지만 일단 각 팀 대표색으로 그래프를 칠하는 데는 성공했습니다.


이렇게 팔레트를 지정하면 항목 숫자가 바뀌어도 계속 색을 유지할 수 있습니다.


그게 무슨 뜻인지 한 번 확인해 볼까요?


이번에는 비교하기 쉽게 그래프를 붙여서 그릴 겁니다.


이럴 때는 'patchwork' 패키지를 사용하시면 좋습니다.


당연히 먼저 이 패키지를 (설치하고) 불러옵니다.

#install.packages('patchwork')
library('patchwork')


그다음 자료에서 홀수행만 골라내서 그래프를 그린 다음 p1이라는 변수에 넣겠습니다.

ggplot(data=ops %>% filter(row_number()%%2==1),
       aes(x=팀, y=ops, fill=팀)) +
  geom_bar(stat='identity') -> p1


마찬가지 방법으로 짝수행만 골라내 p2라는 변수에 넣었습니다.

ggplot(data=ops %>% filterrow_number()%%2==0),
       aes(x=팀, y=ops, fill=팀)) +
  geom_bar(stat='identity') -> p2


그다음 이 두 그래프를 옆으로 나란히 그리면 이렇게 나타납니다.

p1+p2


양쪽 그래프 색깔 순서가 똑같습니다. 그러니까 ggplot2는 기본적으로 색을 처음부터 다시 지정합니다.


그나저나 patchword 패키지 정말 편하지 않나요?


그냥 p1+p2라고 썼을 뿐인데 그래프를 옆으로 나란히 그렸습니다.


이 패키지를 조금 더 알아보고 싶으시면 'ggplot2 그래프 이어 붙이기(feat. patchwork)' 포스트를 읽어 보셔도 좋습니다.


또 '파이프(%>%)' 기호가 등장하고, filter() 함수가 나타나 당황한 분이 계실지도 모르겠습니다.


이런 분들은 '최대한 친절하게 쓴 R로 데이터 뽑아내기(feat. dplyr)'를 읽어보시면 도움이 될 수 있을 겁니다.


다시 본론으로 돌아가서 팔레트를 썼을 때 어떤 상황이 되는지 알아보겠습니다.


이번에는 홀수행만 골라내서 팔레트를 적용한 그래프를 p3,

ggplot(data=ops %>% filter(row_number()%%2==1),
       aes(x=팀, y=ops, fill=팀)) +
  geom_bar(stat='identity')+
  scale_fill_manual(values=kbo_palette) -> p3


그리고 짝수행만 골라내서 역시 팔레트를 적용한 그래프를 p4에 넣겠습니다.

ggplot(data=ops %>% filter(row_number()%%2==0),
       aes(x=팀, y=ops, fill=팀)) +
  geom_bar(stat='identity') +
  scale_fill_manual(values=kbo_palette) -> p4


그리고 patchwork 스타일로 그래프를 그리면

p3+p4


이번에는 팔레트 색깔을 그대로 유지하고 있는 걸 확인할 수 있습니다.


그래서 '항목 이름'='색깔' 형태로 팔레트를 지정하는 겁니다.


고생 많으셨습니다. 원래 처음 우리가 이 포스트에서 연습해 보려고 했던 건 이제 끝났습니다. 


이제부터는 그냥 이미 그래프를 그린 게 아까워 쓰는 보너스입니다.  


'최대한 친절하게 쓴 R로 그래프 그리기(feat. ggplot2)' 포스트에서도 말씀드렸던 것처럼 순위를 그래프로 나타낼 때는 세로 방향으로 그래프를 그리는 게 기본입니다.


ggplot2에서는 coord_flip() 함수를 써서 이 작업을 진행할 수 있습니다.


그냥 우리가 위에서 그래프를 그릴 때 쓴 코드에 coord_flip() 한 줄만 추가하면 됩니다.

ggplot(data=ops, aes(x=팀, y=ops, fill=팀)) +
  geom_bar(stat='identity') +
  scale_fill_manual(values=kbo_palette) +
  coord_flip()


기왕이면 OPS가 높은 팀부터 낮은 팀 순서로 그리면 더 보기가 좋겠죠?


이럴 때는 reorder() 함수를 써서 x축(팀 이름) 순서를 정렬하면 됩니다.


위에 있는 그래프에서는 팀 이름이 y축에 있는 x축 순서를 바꾼다고 말씀드린 건 coord_flip() 함수는 겉으로 보기에만 축을 바꾸기 때문입니다.


reorder() 함수는 기본적으로 reorder(바꾸고 싶은 항목, 기준) 순서로 쓰시면 됩니다.


우리는 팀 이름을 ops 순서에 따라 정렬하고 싶은 거니까 reorder(팀, ops) 형태입니다.


이렇게 정리한 코드를 x축을 지정하는 부분에 넣으면 끝입니다.

ggplot(data=ops, aes(x=reorder(팀, ops), y=ops, fill=팀)) +
  geom_bar(stat='identity') +
  scale_fill_manual(values=kbo_palette) +
  coord_flip()


참고로 tidyverse 생태계에도 이렇게 카테고리(factor) 정리를 도와주는 forcats 패키지가 있습니다.


이 패키지 가운데 fct_reorder() 함수가 reorder()와 같은 방법으로 작동합니다.

ggplot(data=ops, aes(x=fct_reorder(팀, ops), y=ops, fill=팀)) +
  geom_bar(stat='identity') +
  scale_fill_manual(values=kbo_palette) +
  coord_flip()


이렇게 그래프를 그리고 나니 뭐 거슬리는 거 없으십니까?


저는 오른쪽에 있는 범례(legend)가 거슬렸습니다. 그래프 순서하고 맞지 않으니까요.


이 범례 순서를 정렬하는 방법도 x축 항목 정렬과 똑같습니다.


그저 현재 x축이 내림차순 정렬 상태라 기준 변수에 마이너스(-) 부호만 붙여주면 그만입니다.

ggplot(data=ops, aes(x=fct_reorder(팀, ops), y=ops, fill=fct_reorder(팀, -ops))) +
  geom_bar(stat='identity') +
  scale_fill_manual(values=kbo_palette) +
  coord_flip()


이렇게 하고 났더니 (별로 필요한지는 잘 모르겠지만) 범례와 그래프가 같은 순서로 나타났습니다.


그런데 범례 이름이 'fct_reorder(팀, -ops)'로 나와 있으니 역시 또 거슬립니다.


'R에서 묶은 막대 그래프에 레이블 쓰기(feat. poistion_dodge)'에서 설명해 드린 것처럼 이럴 때는 scale_fill_manual() 함수 안에 name 속성을 바꾸면 그만입니다.


원래대로 '팀'이라고 바꾸려면 그냥 name='팀'이라고 덧붙이면 됩니다.

ggplot(data=ops, aes(x=fct_reorder(팀, ops), y=ops, fill=fct_reorder(팀, -ops))) +
  geom_bar(stat='identity') +
  scale_fill_manual(values=kbo_palette, name='팀') +
  coord_flip()


예, 의도했던 대로 바뀌었습니다.


사실 그래프에서는 이런 범례가 큰 의미가 있다고 하기 어렵습니다.


그래도 ggplot2에서 범례 순서를 어떻게 바꾸는지 알아 둔다고 해서 손해보실 일은 없을 겁니다.


이대로 포스트 작성을 끝내려고 했는데 이제는 축 제목이 거슬립니다.


x축 제목을 바꿀 때는 xlab(), y축 제목을 바꿀 때는 ylab()입니다.

ggplot(data=ops, aes(x=fct_reorder(팀, ops), y=ops, fill=fct_reorder(팀, -ops))) +
  geom_bar(stat='identity') +
  scale_fill_manual(values=kbo_palette, name='팀') +
  xlab('팀') + ylab('OPS') +
  coord_flip()


모쪼록 ggplot2 그래프 색깔을 바꾸고 싶은데 못 하고 계셨거나, 범례 순서를 어떻게 바꾸는지 몰라서 애태우셨던 분들께 도움이 되었기를 바랍니다.


그럼 모두들 Happy Charting!


댓글, 2

  • 댓글 수정/삭제
    2020.10.29 09:43

    비밀댓글입니다

    •  수정/삭제 kini
      2020.10.29 16:42 신고

      몇 번째 코드를 말씀하시는 건지 잘 모르겠습니다.

      야구 관련 글은 이 블로그보다 https://kini.kr/ 여기를 찾아주시면 더욱 좋습니다.

account_circle
vpn_key
web

security

mode_edit
KindeR | 카테고리 다른 글 더 보기