R에서 ggplot2 패키지로 그래프를 그리다 보면 레이블(label)을 붙어줘야 할 때가 있습니다.
이럴 때는 기본적으로 geom_text() 또는 geom_label() 함수를 쓰시면 됩니다.
한 번 그래프를 직접 그리면서 두 함수 사용법을 알아보겠습니다.
이번에 우리가 그래프에 쓸 데이터는 2015~2018년 프로야구 10개 구단 팀 타격 결과입니다. 2015년을 기준으로 삼은 건 이해부터 프로야구가 10개 구단 체제로 개편했기 때문.
아래 있는 CSV 파일을 내려받으시고 read.csv() 함수 등으로 불러와 주세요.
kbo <- read.csv('kbo.csv')
head(kbo)
## 연도 팀 타율 출루율 장타력 ## 1 2015 삼성 0.302 0.378 0.469 ## 2 2015 넥센 0.298 0.372 0.486 ## 3 2015 두산 0.290 0.370 0.435 ## 4 2015 NC 0.289 0.367 0.455 ## 5 2015 롯데 0.280 0.356 0.446 ## 6 2015 SK 0.272 0.349 0.410
이어서 할 일은 ggplot2 패키지 불러오기.
library('ggplot2')
그럼 이제 '출루율'을 x축 기준으로, '장타력'을 y축 기준으로 삼는 산점도를 그려보겠습니다. ggplot으로 그래프 그리기에 익숙한 분이시라면 전혀 어려울 게 없습니다.
ggplot(kbo, aes(x=출루율, y=장타력)) +
geom_point()
이제 geom_text()를 써서 각 점에 레이블을 붙이도록 하겠습니다.
레이블로 쓰려고 하는 건 '연도 +팀' 형태. R에서 이렇게 두 문자값을 결합할 때는 paste() 함수가 기본입니다.
paste(kbo$연도, kbo$팀)
[1] "2015 삼성" "2015 넥센" "2015 두산" "2015 NC" "2015 롯데" "2015 SK" [7] "2015 KT" "2015 한화" "2015 LG" "2015 KIA" "2016 두산" "2016 NC" [13] "2016 넥센" "2016 삼성" "2016 롯데" "2016 KIA" "2016 LG" "2016 SK" [19] "2016 한화" "2016 KT" "2017 두산" "2017 KIA" "2017 NC" "2017 넥센" [25] "2017 SK" "2017 롯데" "2017 한화" "2017 삼성" "2017 LG" "2017 KT" [31] "2018 두산" "2018 KIA" "2018 롯데" "2018 SK" "2018 넥센" "2018 LG" [37] "2018 삼성" "2018 KT" "2018 한화" "2018 NC
참고로 paste()는 문자열 사이에 자동으로 공백을 넣는데 이게 싫으시면 paste0()을 쓰시면 됩니다. 나머지 사용법은 똑같습니다.
두 변수를 어떻게 붙이는 줄 알았으니 그래프에 레이블을 붙이는 코드를 써보겠습니다.
ggplot(kbo, aes(x=출루율, y=장타력, label=paste(연도, 팀))) +
geom_point() +
geom_text()
레이블 역시 x, y 좌표 기준이 모두 출루율, 장타력이라서 점 가운데 글씨가 나옵니다. 이럴 때는 hjust(가로), vjust(세로) 속성을 통해 글씨 위치를 조정할 수 있습니다.
한 번 다음처럼 코드를 써보겠습니다.
ggplot(kbo, aes(x=출루율, y=장타력, label=paste(연도, 팀))) +
geom_point() +
geom_text(hjust=-.1)
한결 낫죠? 문제는 hjust, vjust 뒤에 들어가야 할 숫자가 얼마인지 정하기가 쉽지 않다는 것.
기본적으로 이 숫자, 저 숫자를 넣어서 제일 그럴 듯해 보이는 값을 찾을 수밖에 없습니다. 게다가 hjust, vjust는 레이블 위치를 일률적으로 조정하기 때문에 레이블이 겹치는 증상을 해소하지는 못합니다.
이때는 'check_overlap' 속성을 'TRUE'로 바꾸면 도움을 얻을 수 있습니다. 지금 코드 뒤에 'check_overlap=TRUE'를 더해보겠니다.
ggplot(kbo, aes(x=출루율, y=장타력, label=paste(연도, 팀))) +
geom_point() +
geom_text(hjust=-.1, check_overlap=TRUE)
훨씬 깔끔합니다. 단, 이번에도 모든 문제를 해결한 건 아닙니다.
오버랩된 레이블을 정리하다 보니 어떤 점에서는 아예 레이블이 사라지고 말았습니다. 또 레이블이 잘린 지점도 있습니다.
이런 문제를 해결해주는 패키지가 바로 이 포스트 주인공 ggrepel입니다.
새로운 패키지를 쓰시려면 설치하고 불러오는 과정부터 진행해야 합니다. 이렇게 말입니다.
install.packages('ggrepel')
library('ggrepel')
ggrepel을 활용하는 첫 단계는 geom_text() 대신 geom_text_repel() 함수를 쓰는 겁니다. 그냥 geom_text() 자리에 geom_text_repel()을 넣으면 그만입니다.
ggplot(kbo, aes(x=출루율, y=장타력, label=paste(연도, 팀))) +
geom_point() +
geom_text_repel()
깔끔하지 않습니까? 모든 점에 레이블이 붙은 건 물론이고 레이블이 떨어져 있을 때는 선으로 연결하는 친절함까지 느낄 수 있습니다.
그래도 (저처럼) 조금 빡빡하다고 느끼시는 분이 계시다면 여백을 조금 더 주는 것으로 숨통을 틀 수도 있습니다. xlim은 x축 끝을 어디서 어디까지 정하라는 뜻입니다.
ggplot(kbo, aes(x=출루율, y=장타력, label=paste(연도, 팀))) +
geom_point() +
geom_text_repel() +
xlim(0.32, 0.39)
이번에 우리가 그린 산점도는 처음부터 그래도 여유가 있는 편이어서 geom_text()와 geom_text_repel() 사이에 차이가 크지 않다고 생각하시는 분도 계셨을지 모르겠습니다. 그러면 이런 그래프는 어떨까요?
이 정도면 geom_text_repel()을 쓰는 게 확실히 낫다고 생각하지 않으십니까?
아, 혹시 이 그래프를 직접 그려보고 싶은 분이 계시다면 아래 코드를 입력하시면 됩니다.
ggplot(kbo, aes(x=타율, y=1, label=paste(연도, 팀))) +
geom_point(color='#14789D') +
geom_text_repel(nudge_y = 0.05, direction = 'x', angle = 90, vjust = 0, segment.size = 0.2) +
ylim(1, 0.8) +
theme_classic() +
theme(axis.line.y = element_blank(),
axis.ticks.y = element_blank(),
axis.text.y = element_blank(),
axis.title.y = element_blank())
이 예시는 ggrepel 패키지 공식 설명 문서(vignette)에서 가져온 것.
저는 기본적인 사용법만 말씀드렸을 뿐이니 관심 있으신 분은 한 번 들러보시면 조금 더 다양한 예제와 사용 방법을 확인하실 수 있을 겁니다.
그러면 Happy Charting!
댓글,