ggplot2는 dplyr등과 함께
tidyverse라는 R 패키지 집합체에 속해있는 패키지입니다.
tidyverse는 데이터 사이언스에 대한 Hadley Wickham의 철학이
담겨있는 패키지 집합체인데, 특히 ggplot2는 The Grammar of Graphics라는
책에 나온 원칙에 따라 그래프를 그릴 수 있게 해주는 패키지 입니다. 그런데
ggplot2를 처음 접하면 도대체 어떻게 그래프를 그리는 것인지 파악이 어려울
수 있습니다. 그래서 ggplot2가 작동하는 아주 기본적인 원리를
소개해드리려고 합니다. 여기 나온 예제는 https://r4ds.had.co.nz/index.html 에서 많은 부분
가져왔습니다. 먼저 ggplot2를 설치하고 로드해봅시다.
library(ggplot2)
오늘 실습에는 ggplot2 패키지에 내장된 mpg 데이터셋을
이용해서 여러가지 그래프를 그려보겠습니다. 아래 명령문을 실행해서 mpg
데이터셋에 대해 알아봅시다. mpg 데이터셋은 여러가지 차종의 연비와 특성에
대해 기록한 데이터입니다.
?mpg
summary(mpg)
## manufacturer model displ year
## Length:234 Length:234 Min. :1.600 Min. :1999
## Class :character Class :character 1st Qu.:2.400 1st Qu.:1999
## Mode :character Mode :character Median :3.300 Median :2004
## Mean :3.472 Mean :2004
## 3rd Qu.:4.600 3rd Qu.:2008
## Max. :7.000 Max. :2008
## cyl trans drv cty
## Min. :4.000 Length:234 Length:234 Min. : 9.00
## 1st Qu.:4.000 Class :character Class :character 1st Qu.:14.00
## Median :6.000 Mode :character Mode :character Median :17.00
## Mean :5.889 Mean :16.86
## 3rd Qu.:8.000 3rd Qu.:19.00
## Max. :8.000 Max. :35.00
## hwy fl class
## Min. :12.00 Length:234 Length:234
## 1st Qu.:18.00 Class :character Class :character
## Median :24.00 Mode :character Mode :character
## Mean :23.44
## 3rd Qu.:27.00
## Max. :44.00
head(mpg)
## # A tibble: 6 × 11
## manufacturer model displ year cyl trans drv cty hwy fl class
## <chr> <chr> <dbl> <int> <int> <chr> <chr> <int> <int> <chr> <chr>
## 1 audi a4 1.8 1999 4 auto(l5) f 18 29 p compa…
## 2 audi a4 1.8 1999 4 manual(m5) f 21 29 p compa…
## 3 audi a4 2 2008 4 manual(m6) f 20 31 p compa…
## 4 audi a4 2 2008 4 auto(av) f 21 30 p compa…
## 5 audi a4 2.8 1999 6 auto(l5) f 16 26 p compa…
## 6 audi a4 2.8 1999 6 manual(m5) f 18 26 p compa…
ggplot2의 가장 기본적인 구성 요소는 ggplot()과
geom_xxxx() 형식의 이름을 가지고 있는 geom function 입니다.
각 요소는 + 기호로 연결됩니다. ggplot() 안에는
data= 구문으로 데이터셋 이름을 넣어주고, geom function의
종류는 그리려는 그래프의 종류를 의미합니다. 그리고 geom function 안에는
mapping=aes() 구문으로 그리려는 그래프의 x, y, 그 외의 매핑
정보를 입력합니다. 여기에서 mapping= 부분은 생략해도
됩니다.
ggplot(data = <DATA>) + <GEOM_FUNCTION>(mapping = aes(<MAPPINGS>))
한가지 주의할 점은, 코드가 길어져서 다음 줄로 넘어가야 한다면, 반드시
+가 오른쪽 끝에 있어야 합니다.
ggplot2 패키지에 내장된 mpg 데이터셋을
이용해서 가장 간단한 산점도를 하나 그려보겠습니다. 산점도를 그려주는
geom function은 geom_point() 입니다.
ggplot(data=mpg) + geom_point(aes(x=displ, y=hwy))
어떤 범주형 변수의 범주별로 다른 색깔의 점을 찍고 싶다면, 역시
aes() 구문 안에 지정하면 됩니다. 여기에서는 차종을 의미하는
class라는 변수를 이용해서, 차종별로 다른 색깔을
찍어봅시다.
ggplot(data=mpg) + geom_point(aes(x=displ, y=hwy, color=class))
모든 점을 파랗게 만들고 싶다면 어떻게 해야할까요? 아래의 두 그래프와 코드의 차이점을 잘 보세요.
ggplot(data=mpg) + geom_point(aes(x=displ, y=hwy), color="blue")
ggplot(data=mpg) + geom_point(aes(x=displ, y=hwy, color="blue"))
흑백으로 프린트할 경우 색깔보다는 shape으로 구분하는 게 좋겠지요.
그런데 6개를 초과하는 shape은 ggplot2가 자동으로
없애버립니다. 그럴 경우 scale_shape_manual() 함수를
추가해서 수동으로 shape을 지정해줘야 합니다.
ggplot(data=mpg) + geom_point(aes(x=displ, y=hwy, shape=class))
## Warning: The shape palette can deal with a maximum of 6 discrete values because more
## than 6 becomes difficult to discriminate
## ℹ you have requested 7 values. Consider specifying shapes manually if you need
## that many have them.
## Warning: Removed 62 rows containing missing values (`geom_point()`).
ggplot(data=mpg) + geom_point(aes(x=displ, y=hwy, shape=class)) +
scale_shape_manual(values=1:7)
아예 class 별로 산점도를 따로따로 그리고 싶을 수도 있죠. 그럴 경우
facet_wrap() 함수를 뒤에 +로 연결해줍니다.
facet_wrap() 함수안에 nrow= 또는
ncol= 구문을 이용해서 그래프를 몇행으로 또는 몇열로
배열할지 지정할 수 있습니다.
ggplot(data=mpg) + geom_point(aes(x=displ, y=hwy)) + facet_wrap(~class)
ggplot(data=mpg) + geom_point(aes(x=displ, y=hwy)) + facet_wrap(~class, nrow=2)
잠시 class를 잊어버리고, 다시 displ과
hwy간의 산점도로 돌아와봅시다. 제목을 붙이고, x축, y축
범위나 레이블을 바꾸거나 tick mark의 값을 지정하는 것 모두 아래와 같이,
기본 형태에 +로 해당 요소들을 덧붙여주는 식으로
이루어집니다.
ggplot(data=mpg) + geom_point(aes(x=displ, y=hwy)) +
ggtitle("Engine displacement vs. Highway MPG") +
xlab("Highway MPG") + ylab("Engine displacement (liters)") +
scale_x_continuous(limits=c(1, 7), breaks=c(1:7)) +
scale_y_continuous(limits=c(10, 50))
\(~\)
이제 다른 종류의 geom function들을 살펴보겠습니다. 먼저 스무딩한
곡선을 보여주는 geom_smooth() 입니다.
ggplot(data=mpg) + geom_smooth(aes(x=displ, y=hwy))
## `geom_smooth()` using method = 'loess' and formula = 'y ~ x'
이 그래프 역시, 범주형 변수의 범주 별로 다른 곡선을 그릴 수 있습니다.
색깔을 달리하거나, 선의 모양을 달리할 수 있습니다.
geom_point()와 마찬가지로 aes() 안에
지정해줍니다.
ggplot(data=mpg) + geom_smooth(aes(x=displ, y=hwy, color=drv))
## `geom_smooth()` using method = 'loess' and formula = 'y ~ x'
ggplot(data=mpg) + geom_smooth(aes(x=displ, y=hwy, linetype=drv))
## `geom_smooth()` using method = 'loess' and formula = 'y ~ x'
만약, 원 자료의 산점도와 스무딩 곡선을 한 그래프에 같이 보여주려면
어떻게 하면 될까요? +로 두가지 geom function을 다 붙여주면
됩니다.
ggplot(data=mpg) + geom_point(aes(x=displ, y=hwy)) +
geom_smooth(aes(x=displ, y=hwy))
## `geom_smooth()` using method = 'loess' and formula = 'y ~ x'
그런데 두개의 geom function 안에 똑같은 구문들이 들어가있죠? 이렇게
공통된 aesthetic 요소가 있으면, ggplot() 안으로 옮겨주어도
됩니다. ggplot() 안에서 정의한 mapping은 global
mapping이라고 해서, 그 뒤에 따라 붙는 모든 geom function에 공통으로
적용됩니다. 즉, 아래의 코드는, 위의 그래프와 완전히 똑같은 그래프를
그려냅니다.
ggplot(data=mpg, aes(x=displ, y=hwy)) + geom_point() + geom_smooth()
## `geom_smooth()` using method = 'loess' and formula = 'y ~ x'
그런데 global mapping을 정의했어도, local mapping을 추가로 적용할 수도 있습니다.
ggplot(data=mpg, aes(x=displ, y=hwy)) + geom_point(aes(color=class)) + geom_smooth()
## `geom_smooth()` using method = 'loess' and formula = 'y ~ x'
이번엔 histogram을 그리는 geom function입니다. 히스토그램이 무엇인가
잘 생각해보시면, 히스토그램의 세로축 값은 도수를 표시하는 것이므로 따로
지정해주지 않아도 자동으로 결정됩니다. 따라서 aes() 구문
안에 y= 부분은 쓸 필요가 없습니다.
ggplot(data=mpg) + geom_histogram(aes(x=hwy))
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
그런데 히스토그램의 막대가 서로 붙어서 까맣게 칠해져있으니 각 막대가
나타내는 구간을 파악하기 어렵죠. 그래서 막대의 경계선과 막대 내부의
색깔을 다르게 지정해주는 것이 좋습니다. 이것은 데이터를 매핑하는 것에
관한 정보가 아니므로 aes() 구문 밖에 지정해줍니다. 막대의
경계선의 색은 color= 구문으로, 막대 내부의 색은
fill= 구문으로 지정해줍니다.
ggplot(data=mpg) + geom_histogram(aes(x=hwy), fill="skyblue", color="black")
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
ggplot2가 자동으로 정해주는 히스토그램의 구간은 너무 좁은 경향이
있습니다. 구간의 경계값을 직접 설정하고 싶을 때는 breaks=
구문을 이용하면 됩니다.
ggplot(data=mpg) + geom_histogram(aes(x=hwy), fill="skyblue", color="black",
breaks=seq(10, 44, 2))
이번에는 box plot(상자그림)을 그리는 방법을 알아봅시다.
geom_boxplot() 함수를 이용하면 됩니다.
ggplot(data=mpg) + geom_boxplot(aes(x=class, y=hwy))
좀 정신이 없으니, hwy의 중앙값 기준으로 정렬하는
코드입니다.
ggplot(data=mpg) + geom_boxplot(aes(x=reorder(class, hwy, FUN=median), y=hwy))
class 이름이 길어서 옆으로 눞이는 것이 좋을 수도 있겠죠.
coord_flip() 을 뒤에 연결해주면 됩니다.
ggplot(data=mpg) + geom_boxplot(aes(x=reorder(class, hwy, FUN=median), y=hwy)) +
coord_flip()
이번에는 범주형 변수의 범주별 카운트를 보여주는 bar
plot(막대그래프)을 그리는 방법을 보여드리겠습니다. 이번에는
ggplot2에 내장된 diamonds 데이터셋을 이용합니다. 여러가지
다이아몬드의 가격 및 특성을 보여주는 데이터입니다. 이 데이터에서 각 cut
별 다이아몬드의 갯수를 나타내는 bar plot 을 그려봅시다..막대그래프는
geom_bar() 함수를 이용하여 그릴 수 있습니다.
ggplot(data=diamonds) + geom_bar(aes(x=cut))
막대의 색깔을 바꾸려면 히스토그램과 마찬가지로 fill=
구문을 이용합니다.
ggplot(data=diamonds) + geom_bar(aes(x=cut), fill="pink")
막대의 색깔을 이용하여 제 2의 변수에 대한 정보를 표시할 수도
있습니다. 각 컷 별로 투명도(clarity)의 분포를 보고 싶으면, 아래와 같이
aes() 안에 fill= 구문으로 지정해줍니다.
ggplot(data=diamonds) + geom_bar(aes(x=cut, fill=clarity))
마지막으로 선 그래프입니다. ggplot2에 내장된 economics
데이터는 시계열 자료입니다. 날짜를 x축으로 하고, 날짜가 지남에 따라
실업률이 변하는 추세를 선그래프로 그리는 코드입니다. 선그래프는
geom_line() 함수로 그립니다.
economics
## # A tibble: 574 × 6
## date pce pop psavert uempmed unemploy
## <date> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1967-07-01 507. 198712 12.6 4.5 2944
## 2 1967-08-01 510. 198911 12.6 4.7 2945
## 3 1967-09-01 516. 199113 11.9 4.6 2958
## 4 1967-10-01 512. 199311 12.9 4.9 3143
## 5 1967-11-01 517. 199498 12.8 4.7 3066
## 6 1967-12-01 525. 199657 11.8 4.8 3018
## 7 1968-01-01 531. 199808 11.7 5.1 2878
## 8 1968-02-01 534. 199920 12.3 4.5 3001
## 9 1968-03-01 544. 200056 11.7 4.1 2877
## 10 1968-04-01 544 200208 12.3 4.6 2709
## # ℹ 564 more rows
ggplot(economics, aes(x=date, y=unemploy)) + geom_line()
linetype= 옵션으로 선의 모양을, color=
옵션으로 선의 색을 지정할 수 있습니다.
ggplot(economics, aes(x=date, y=unemploy)) + geom_line(linetype="dashed", color="forestgreen")
그래프에서 점, 선, 면의 모양, 위치, 크기 등과 마찬가지로 색상 역시
데이터를 전달하는 하나의 채널로 사용될 수 있습니다. 그래서 구분이 쉽고
보기에 좋은 색상을 잘 정하는 것도 중요한데, 수동으로 색상을 정하기보다는
전문가들이 선정해 놓은 컬러맵을 사용하는 것이 더 편리하고 보기 좋을 수
있습니다. ggplot2 패키지는 다양한 컬러맵을 불러오는 기능이
있는데, 그 중 RcolorBrewer라는 패키지에 들어있는 컬러맵을
불러오는 방법을 알아보겠습니다.
먼저 RColorBrewer 패키지를 설치하고 불러옵니다.
library(RColorBrewer)
이 패키지에 있는 모든 컬러맵을 보려면 아래의 명령문을 실행하면 됩니다.
display.brewer.all()
마음에 드는 컬러맵이 있으면, 그 컬러맵에서 몇개의 색을 뽑아내고 싶은지 지정해서 헥사코드를 뽑아낼 수 있습니다. 아래의 코드는 YlGn 컬러맵에서 7개의 색의 헥사코드를 뽑아내는 코드입니다.
brewer.pal(7, "YlGn")
## [1] "#FFFFCC" "#D9F0A3" "#ADDD8E" "#78C679" "#41AB5D" "#238443" "#005A32"
아래는 YlGn의 컬러맵에서 뽑아낸 7개의 색을 시각화하는 코드입니다.
display.brewer.pal(7, "YlGn")
처음에 그렸던 mpg 데이터셋의 displ와 hwy의 산점도로 다시
돌아가봅시다. 그 산점도에서 각 점의 색이 cty의 값을 나타내도록 하려면
어떻게 해야할까요? 아래와 같이 aes() 구문 안에
color=cty라고 써주면, ggplot2가 자동으로 컬러맵을 선정해서
그려줍니다.
ggplot(data=mpg) + geom_point(aes(x=displ, y=hwy, color=cty))
자동으로 선정된 컬러맵이 아니라, RColorBrewer에서 내가 고른 컬러맵을
이용하려면, scale_color_distiller() 함수를 이용하여 컬러맵
이름을 입력하면 됩니다.
ggplot(data=mpg) + geom_point(aes(x=displ, y=hwy, color=cty)) + scale_color_distiller(palette="YlGn")
대체로 점이나 선의 색을 지정할 때
scale_color_distiller() 함수를 쓴다고 생각하시면 됩니다.
면의 색을 지정할 때는 scale_scale_fill_brewer() 함수를
씁니다. 아래는 diamonds 데이터의 cut 변수의 분포를 나타내는
막대그래프에서 각 막대의 색을 지정하는 코드입니다.
ggplot(data=diamonds) + geom_bar(aes(x=cut, fill=cut)) +
scale_fill_brewer(palette="YlGn")
이 정도면 ggplot2를 이용하여 기본적인 그림은 그리실 수
있고, 다른 사람의 코드를 보고 파악하시는데 큰 어려움은 없으리라
생각됩니다.