범주형 변수의 요인(factor)별로 면 분할된 상태의 그래프에 텍스트 주석을 넣으려고 아래와 같이 하면 라벨 길이가 다르다면서 에러가 납니다.
> # 텍스트 라벨 넣으려면 에러 발생
> # Error: Incompatible lengths for set aesthetics: label
> g1 +
+ annotate("text", x=1, y=7, label=c("Setosa", "Versicolor", "Virginica"))
Error: Incompatible lengths for set aesthetics: label
범주형 변수의 요인(factor)별로 면 분할된 상태의 그래프에 텍스트 주석을 넣으려고 하려면 annotate() 함수로는 안되구요, 라벨을 넣으려는 내용을 데이터프레임으로 미리 만들어놓고 geom_text()로 라벨을 집어넣어야 합니다. 아래 예제는 Species 이름을 각 각 텍스트로 넣어보는 예입니다.
> install.packages("sqldf")> library(sqldf)
> > mean_iris <- sqldf('select "Species",
+ avg("Petal.Width") as "mean_Petal.Width",
+ avg("Petal.Length") as "mean_Petal.Length"
+ from iris
+ group by Species
+ order by Species
+ ')
> > mean_iris
Species mean_Petal.Width mean_Petal.Length
1 setosa 0.246 1.462
2 versicolor 1.326 4.260
3 virginica 2.026 5.552
그동안 R로 다양한 그래프를 그리는 방법을 알아보았습니다. R로 그래프를 그렸다면, 보는 이의 가독성, 해석의 용이성을 높여주기 위해서 그래프 위에 텍스트, 가로선/세로선/대각선, 화살표, 음영 사각형, 제목 등과 같이 추가로 정보를 제공하거나 강조를 하고 싶은 부분에 주석을 달고 싶을 때가 있습니다.
- 화살표 : annotate("segment", arrow=arrow()) , with grid package
- 음영 사각형 : annotate("rect")
- 제목 : ggtitle()
매번의 R 그래프/시각화 포스팅마다 주석 다는 방법을 간간이 곁들여서 소개해드리기는 했는데요, 이번 포스팅에서는 주석 다는 방법에 대해서 포괄적이고 종합적으로 정리를 해서 바로 찾아보기 편하도록 정리를 해보았습니다.
예제로 사용할 데이터는 Base Package에 내장되어 있는 iris 데이터 프레임의 Petal.Width, Petal.Length, Species 의 세개 변수를 사용하겠습니다. (iris 데이터셋은 데이터 마이닝 실습에 아주 많이 사용되는 데이터셋으로서, iris 꽃 품종 중 setosa 50개, versicolor 50개, virginica 50개를 꽃잎의 넓이와 길이를 측정해놓은 데이터셋입니다)
이번 포스팅에서는 R ggplot2에서 그래프 색깔 설정 (colour setting), 조절하는 방법에 대해서 알아보겠습니다. 이전의 각 그래프 종류별로 소개한 내용에도 색깔 지정에 대한 내용이 조금씩 포함되어 있기는 합니다만, 이번 포스팅에서는 색깔 설정에 대한 경우의 수를 종합적으로 포괄해서 정리를 해보았습니다.
그래프에서 색깔을 특정 변수의 변화와 align하게 되면 x축과 y축의 2차원에 색깔이라는 차원을 추가함으로써 3차원의 정보를 제공할 수 있습니다. 회사 업무 보고서에 엑셀로 그린 그래프를 많이 사용하고는 하는데요, x축과 y축의 2차원을 넘어서는, 특정 조건에 따라서 색깔이나 모양을 달리해야 하는 경우라면 엑셀로 그래프를 그리는 것이 거의 불가능하게 됩니다. 이때 R이 데이터 전처리/변환부터 해서 인쇄용으로 바로 사용해도 좋을 만큼의 고품질의 그래프를 그리는데 아주 특출난 역할을 할 수 있습니다. R 그래프에서 색깔을 자유자재로 사용할 수 있다면 미적으로도 보기에 좋겠지요?!
이번 예제에서 사용할 데이터는 MASS 패키지에 내장되어 있는 Cars93 데이터 프레임의 차 무게(Weight)와 고속도로연비(MPG.highway), 차 가(Price), 실린더 개수(Cylinders)의 4개 변수를 사용하겠습니다.
ggplot2 그래프를 그렸을 때 x축이나 y축의 디폴트 값을 사용해도 무리가 없는 경우가 많기는 합니다만,
분석가가 x축이나 y축을 좀더 사용하는 목적에 맞게 설정을 조정하고 싶을 때가 있습니다.
이때 사용할 수 있는 ggplot2의 함수 3가지를 알아보도록 하겠습니다.
(1) 1:1 의 비율로 x축과 y축 설정
: coord_fixed()
(2) 일정한 간격으로 x축, y축 설정
: scale_x_continuous(breaks=seq())
(3) 분석가 마음대로 x축, y축 설정
: scale_x_continuous(breaks=c())
예제로 사용할 데이터는 MASS 패키지에 내장되어 있는 Cars93 데이터 프레임의 도시연비(MPG.city), 고속도로연비(MPG.highway)가 되겠습니다. scale이 연비로서 서로 같은 변수를 선택하였으며, 산점도를 그려보면서 x축, y축 설정을 바꿔보도록 하겠습니다.
ggplot2는 신규 설치 및 호출이 필요한 패키지이므로 아래와 같은 사전 절차가 필요합니다.
> # ggplot2 설치 및 호출
> install.packages("ggplot2")
> library(ggplot2)
순서대로 하나씩 살펴보겠습니다. 함수 옵션을 바꿔줌에 따라서 x축, y축 결과가 어떻게 바뀌는지 살펴보시고, 필요로 하는 함수 옵션을 선택해서 사용하시면 되겠습니다.
(0) Default setting
> # default setting of x and y axis
> ggplot(Cars93, aes(x=MPG.city, y=MPG.highway)) +
+ geom_point(shape=21, colour="black", size=3) +
+ ggtitle("default setting of x and y axis")
(1) 1:1 의 비율로 x축과 y축 설정 : coord_fixed()
> # 1:1 proportion of x and y axis : coord_fixed()
> ggplot(Cars93, aes(x=MPG.city, y=MPG.highway)) +
+ geom_point(shape=21, colour="black", size=3) +
+ coord_fixed() +
+ ggtitle("1:1 proportion of x and y axis : coord_fixed()")
(2) 일정한 간격으로 x축과 y축 설정 : scale_x_continuous(breaks=seq())
> # manual setting with fixed interval of x and y axis : scale_x_continuous(breaks=seq())
> ggplot(Cars93, aes(x=MPG.city, y=MPG.highway)) +
+ geom_point(shape=21, colour="black", size=3) +
+ coord_fixed() +
+ scale_x_continuous(breaks=seq(0, 80, 5)) +
+ scale_y_continuous(breaks=seq(0, 80, 5)) +
+ ggtitle("manual setting with fixed interval of x and y axis : scale_x_continuous(breaks=seq())")
(3) 분석가 마음대로 x축과 y축 설정 : scale_x_continuous(breaks=c())
> # manual setting of x and y axis : scale_x_continuous(breaks=c())
> ggplot(Cars93, aes(x=MPG.city, y=MPG.highway)) +
+ geom_point(shape=21, colour="black", size=3) +
+ coord_fixed() +
+ scale_x_continuous(breaks=c(10, 15, 20, 25, 30, 40)) +
+ scale_y_continuous(breaks=c(20, 25, 30, 40, 50)) +
+ ggtitle("manual setting of x and y axis : scale_x_continuous(breaks=c())")
함수 옵션을 바꿔줌에 따라서 x축, y축 결과가 어떻게 바뀌는지 살펴보시고, 필요로 하는 함수 옵션을 선택해서 사용하시면 되겠습니다.
그룹(집단, 요인) 간의 데이터 분포 형태, 변화 추이 등을 비교 분석하기에 유용한 방법으로 비교하려는 축을 기준으로 면을 분할하여 그래프를 그룹 간 비교하는 방법이 있습니다.
Lattice 패키지에서는 Trellis 를 사용하는데요, ggplot2 패키지에서는 facet_grid() 함수와 facet_wrap() 함수를 사용하여 면 분할을 구현할 수 있습니다.
Base Graphics 패키지에서는 par() 함수를 사용해서 면 분할을 지정해줄 수 있습니다만, x축과 y축의 scale이 들쭉날쭉해서 직접적으로 서로 비교하기가 곤란하거나, y축의 min, max 값이 그룹 간 숫자를 모두 감안해서 자동 설정되는 것이 아니다보니 분석가가 미리 y축 값의 범위를 계산해보고, 혹은 그려보고 나서 y축 값을 세팅해줘야 하므로 lattice나 ggplot2 대비 불편합니다. 따라서 집단간 비교를 위한 면 분할이 필요한 경우 ggplot2나 lattice 패키지를 권합니다.
MASS 패키지 내 무게(Weight), 고속도로연비(MPG.highway), 차종(Type, 범주형), 생산국가(Origin, 범주형) 의 4개 변수를 사용해서, x축에 무게(Weight), y축에 고속도로연비(MPG.highway), 그리고 면 분할의 기준으로 범주형 변수인 차종(Type)과 생산국가(Origin) 변수를 사용하겠습니다.
facet_grid()를 먼저 예제를 보이고, 그 후에 facet_wrap()의 예제를 들겠습니다. 두 함수가 비슷하면서도 조금 다릅니다. 분석가가 필요로 하는 아웃풋 이미지에 맞게 골라서 사용하면 되겠습니다.
이전 포스팅에서 x축과 y축의 값에 따라 산점도 그리는 방법을 알아보았다면, 이번 포스팅에서는 여기에 더해서 z라는 제 3의 변수에 비례해서 점의 크기를 변화시켜서 그린 그래프가 버블 그래프 (Bubble Chart) 입니다. 산점도가 2차원의 그래프(단, 색깔이나 모양 조건을 추가하면 3차원 정보 제공 가능)라면, 버블 그래프 (Bubble Chart)는 3차원의 그래프가 되어 지면에 보다 많은 정보량을 제공할 수 있는 장점이 있습니다.
ggplot2에서는 산점도, 점 그래프를 그리는 geom_point() 함수와 함께 scale_size_area() 함수를 같이 사용하면 버블 그래프 (Bubble Chart)를 그릴 수가 있습니다.
MASS 패키지의 Cars93 데이터 프레임 내에 차 모델명(Model), 차종(Type), 무게(Weight), 고속도로연비(MPG.highway), 가격(Price)의 5개 변수를 사용하여 버블 그래프를 그려보겠습니다. 데이터가 너무 많으면 버블 그래프를 그릴 때 겹쳐 보여서 보기 싫으므로 차종(Type)에서 "compact"와 "large"의 두 종만 선별해서 예를 들어보겠습니다.
ggplot2의 geom_point()와 scale_size_area() 함수를 사용하여 버블 그래프 (bubble chart)를 그려보겠습니다. ggplot2는 별도의 설치와 호출이 필요한 패키지이므로 아래와 같이 install.packages()와 library()로 설치 및 호출을 먼저 해야 합니다.
> install.packages("ggplot2")
Installing package into ‘C:/Users/user/Documents/R/win-library/3.2’
(as ‘lib’ is unspecified)
trying URL 'http://cran.rstudio.com/bin/windows/contrib/3.2/ggplot2_1.0.1.zip'
Content type 'application/zip' length 2676272 bytes (2.6 MB)
downloaded 2.6 MB
package ‘ggplot2’ successfully unpacked and MD5 sums checked
The downloaded binary packages are in
C:\Users\user\AppData\Local\Temp\RtmpKeoxEa\downloaded_packages
> library(ggplot2)
x축에는 무게(Weight)를, y축에는 고속도로연비(MPG.highway)를, 원의 크기는 가격(Price)를 설정하였습니다. 그리고 겹치는 부분이 있어서 alpha=0.5 로 해서 반투명하게 하였습니다. scale_size_area 에서 원의 크기의 최대값(max)을 15개 한정을 지었으며, geom_text() 함수를 활용해 vjust=1로 해서 x축 값에 align되고 y값은 MPG.highway값에 살짝 조정을 가해서 label로는 모델명(Model) 변수값을 가져다가 라벨링을 하였습니다.
ggplot2로 막대그래프를 그렸는데 데이터가 양수와 음수로 구분이 되는 경우 그래프의 가독성을 높이기 위해서 양수냐, 음수냐에 따라 색상을 다르게 하고 싶을 때가 있습니다.
이번 포스팅에서는 R에 내장되어 있는 airquaility 데이터셋 (뉴욕의 1973년 5월~9월까지의 daily air quality measurements) 에서 5월달 온도(Temp) 만을 가져온 후에, 5월달 daily 온도의 1차 차분 데이터를 만들어서 막대그래프를 그려보도록 하겠습니다.
> str(airquality)
'data.frame': 153 obs. of 6 variables:
$ Ozone : int 41 36 12 18 NA 28 23 19 8 NA ...
$ Solar.R: int 190 118 149 313 NA NA 299 99 19 194 ...
$ Wind : num 7.4 8 12.6 11.5 14.3 14.9 8.6 13.8 20.1 8.6 ...
$ Temp : int 67 72 74 62 56 66 65 59 61 69 ...
$ Month : int 5 5 5 5 5 5 5 5 5 5 ...
$ Day : int 1 2 3 4 5 6 7 8 9 10 ...
> sum(is.na(airquality$Temp))
[1] 0
>
> # 5월 온도만 선택
> May <- subset(airquality, select = c(Month, Day, Temp), subset = (Month == "5"))
>
온도의 1차 차분은 diff(변수, lag=차수) 함수를 사용합니다. 아래는 1차 차분을 하였으므로 5월1일은 빼고, 5월2일부터 5월31일까지의 날짜만 가져온 후에, 날짜와 온도 1차 차분한 값을 data frame으로 묶었습니다. 그 후에 ifelse() 함수를 사용해서 온도 1차 차분 값이 0 이상이면 "PLUS", 0 미만이면 "MINUS"라는 구분자 변수를 새로 생성하였습니다.
> attach(May_Temp_Diff.df)> May_Temp_Diff.df$plus_minus <- ifelse(May_Temp_Diff >= 0, "PLUS", "MINUS")
> May_Temp_Diff.df
May_Day May_Temp_Diff plus_minus
1 2 5 PLUS
2 3 2 PLUS
3 4 -12 MINUS
4 5 -6 MINUS
5 6 10 PLUS
6 7 -1 MINUS
7 8 -6 MINUS
8 9 2 PLUS
9 10 8 PLUS
10 11 5 PLUS
11 12 -5 MINUS
12 13 -3 MINUS
13 14 2 PLUS
14 15 -10 MINUS
15 16 6 PLUS
16 17 2 PLUS
17 18 -9 MINUS
18 19 11 PLUS
19 20 -6 MINUS
20 21 -3 MINUS
21 22 14 PLUS
22 23 -12 MINUS
23 24 0 PLUS
24 25 -4 MINUS
25 26 1 PLUS
26 27 -1 MINUS
27 28 10 PLUS
28 29 14 PLUS
29 30 -2 MINUS
30 31 -3 MINUS
> detach(May_Temp_Diff.df)
ggplot2 패키지는 사용자가 추가로 설치해야 합니다. intall.packages()함수로 설치하고 library() 함수로 호출해보겠습니다.
> install.packages("ggplot2")
> library(ggplot2)
이제 준비가 다 되었습니다. 1차 차분한 5월달의 온도에 대해서 양수(전날 보다 온도 상승)는 빨간색, 음수(전날보다 온도 하락)는 파란색으로 막대 그래프를 그려보겠습니다. aes(fill=구분자 변수) 함수를 사용하고, 색깔지정은 scale_fill_manual(values=c(색깔1, 색깔2)) 로 지정해주면 됩니다.
> # 양수는 빨간색, 음수는 파란색으로 막대 색 구분
> ggplot(data=May_Temp_Diff.df, aes(x=May_Day, y=May_Temp_Diff, fill=plus_minus)) +
+ geom_bar(stat="identity", position="identity", colour="white", width=0.2) + # width 막대 폭 좁게
+ scale_fill_manual(values=c("blue", "red"), guide=FALSE) + # guide=F 범례 생략
+ ggtitle("1st order differenced Temp of May")
막대 폭이 너무 가늘어서 보기 싫다면, 막대 폭을 좀더 넓히고 싶다면 geom_bar(width=숫자) 함수를 사용하면 됩니다.
> # width 막대 폭 넓게
> ggplot(data=May_Temp_Diff.df, aes(x=May_Day, y=May_Temp_Diff, fill=plus_minus)) +
+ geom_bar(stat="identity", position="identity", colour="white", width=1) + # width 막대 폭 넓게
+ scale_fill_manual(values=c("blue", "red"), guide=FALSE) + # guide=F 범례 생략
+ ggtitle("1st order differenced Temp of May")
다음으로, 위의 그래프에서 보면 ggplot2 가 알아서 x축을 10, 20, 30으로 해서 10일 간격으로 설정해서 그래프를 그렸는데요, 이를 좀더 세분화하고 싶다면 scale_x_continuous(breaks=c(숫자, 숫자...)) 로 지정해주면 됩니다.
> trade_stat <- read.csv("C:/Users/user/Documents/R/trade_stat_07_14.csv", # 경로 설정
+ header = TRUE)
> > > trade_stat <- transform(trade_stat, Year = substr(Time, 1, 4))
> > sapply(trade_stat, class)
Time export_amt import_amt Year
"numeric" "integer" "integer" "factor"
> > library(sqldf)
> # 한국 수/출입 무역금액, 단위: 1B$
> trade_stat_Year <- sqldf('select Year,
+ sum(export_amt)/100000 as exp_amt_Year,
+ sum(import_amt)/100000 as imp_amt_Year
+ from trade_stat
+ group by Year
+ order by Year
+ ')
> trade_stat_Year
Year exp_amt_Year imp_amt_Year
1 2007 3714 3568
2 2008 4220 4352
3 2009 3635 3230
4 2010 4663 4252
5 2011 5552 5244
6 2012 5478 5195
7 2013 5596 5155
8 2014 5726 5255
여기까지 했는데도 누적 영역 그래프를 그리기에 딱 맞는 데이터 형태가 아니라서 reshape 패키지의 melt() 함수를 사용하여 데이터를 현재의 가로로 늘어져있는 exp_amt_Year, imp_amt_Year 변수를 -> 세로로 세워서 데이터 구조를 변경해보겠습니다.
그 다음에 variable -> trade_cd (수입, 수출 구분 코드), value -> amount_B (무역금액, 단위 : 1B$) 로 변수명을 변경하였습니다.
이제 드디어 누적 영역 그래프를 그릴 데이터 셋 준비가 다 되었군요. ggplot2의 geom_area() 함수를 사용하여 우선 값 기준으로 그리고, 다음으로 비율 기준으로도 그려보겠습니다.
geom_area(colour=NA)로 하고 geom_line(position="stack")으로 해서 양 옆에 선은 트여주고, 영역 간 경계선은 그려주었습니다.
> # 누적 영역 그래프 그리기
> ggplot(trade_stat_Year_melt, aes(x=Year, y=amount_B, fill=trade_cd, group=trade_cd)) +
+ geom_area(colour=NA, alpha=0.5) + # alpha 투명도
+ scale_fill_brewer(palette="Blues") +
+ geom_line(position="stack", size=0.3) +
+ ggtitle("Stacked Area Plot of Trade (Import, Export) from 2007 to 2014")
ymax not defined: adjusting position using y instead
aes(arder=desc()) 를 사용하여 위의 영역 구분 그룹의 순서를 바꿀 수도 있습니다. 위의 예제에서는 exp_amt_Year (수출액)이 아래에 위치했습니다만, 아래 예제에서는 exp_amt_Year(수출액)이 위로 위치가 바뀌었음을 알 수 있습니다.
> # 누적 영역 순서 바꾸기
> library(plyr) # desc() 함수 사용 위해 필요
> ggplot(trade_stat_Year_melt, aes(x=Year, y=amount_B, fill=trade_cd, group=trade_cd,
+ order=desc(trade_cd))) + # 누적 영역 순서 내림차순 정렬
+ geom_area(colour=NA, alpha=0.5) + # alpha 투명도
+ scale_fill_brewer(palette="Blues") +
+ geom_line(position="stack", size=0.3) +
+ ggtitle("Stacked Area Plot of Trade (Import, Export) from 2007 to 2014")
ymax not defined: adjusting position using y instead
이번에는 비율 기준으로 해서 누적 영역 그래프를 그려보겠습니다. 이를 위해서는 데이터셋에서 Year 별로 비율을 계산해주어야 합니다. 데이터 프레임에서 사칙연산을 써가면서 transform() 함수로 step-by-step 해나갈 수도 있는데요, plyr패키지의 ddply() 함수를 사용하면 놀랍도록 간편하게 원하는 비율 값을 구할 수 있습니다.
위의 trade_prop 변수를 활용해서 비율 누적 영역 그래프(Propostion stacked area plot)을 그려보도록 하겠습니다. 값을 기준으로 했을 때와 script는 동일하며, y값 자리에 trade_prop (수출입 무역 비율) 변수로 바꾸어주기만 하면 됩니다.
그래프 뒤에 단위 격자가 보이도록 geom_area(alpha=0.5) 로 해서 약간 투명하게 처리했습니다.
> # 비율 누적 영역 그래프 그리기
> library(plyr) # desc() 함수 사용 위해 필요
> ggplot(trade_stat_Year_melt_prop, aes(x=Year, y=trade_prop, fill=trade_cd, group=trade_cd,
+ order=desc(trade_cd))) + # 누적 영역 순서 내림차순 정렬
+ geom_area(colour=NA, alpha=0.5) + # alpha 투명도
+ scale_fill_brewer(palette="Blues") +
+ geom_line(position="stack", size=0.3) +
+ ggtitle("Stacked Area Plot of Trade Proportion (Import, Export) from 2007 to 2014")
ymax not defined: adjusting position using y instead
예전 포스팅 중에서 일변량 연속형 변수에 대해 ggplot2로 막대 그래프 그리는 법을 소개했었는데요, 막대 그래프의 훌륭한 대안으로서 점 그래프(Dot Plot)이 있습니다.
Cleveland and McGill (1984) 이 “Graphical Methods for Data Presentation: Full Scale Breaks, Dot Charts, and Multibased Logging.” 이라는 논문에서 막대 그래프 대비 점 그래프가 데이터 해석, 가독성에서 가지는 우수성을 소개하면서 Cleveland Dot Plot 이라고도 많이 불리는 그래프입니다.
분석에 활용할 데이터는 MASS 패키지 내 Cars93 데이터 프레임에서, 차종(Type), 모델(Model), Max.Price, Min.Price의 4개 변수를 사용하겠으며, 관측치 개수가 많아서 화면 하나에 전부 뿌리기에는 너무 많으므로 차종(Type)의 Level 중에서 "Large", "Midsize", "Small" 만 선별하고 "Compact", "Sproty", "Van"은 제외하도록 하겠습니다.
geom_point() 함수를 사용하여 클리브랜드 점 그래프(Cleveland dot plot)을 그려보겠습니다.
aes(y = reorder(Model, Max.Price)) 를 사용해서 y축에 사용할 Model 을 Max.Price 를 기준으로 정렬을 하였기 때문에 아래처럼 Max.Price가 높은 것부터 낮은 것으로 정렬이 된 채로 점 그래프가 제시되었습니다.
aes(shape = Type) 을 적용하여서 Type(Large, Midsize, Small) 별로 모양(shape)을 달리해서 제시하였습니다.
> # Cleveland dot plot of Max Price of Models with different shape by Type > library(ggplot2) > > ggplot(Cars93_P, aes(x = Max.Price, y = reorder(Model, Max.Price), shape = Type)) + + geom_point(size = 3, colour = "blue") + + theme_bw() + # background 색 없애기 + theme(panel.grid.major.x = element_blank(), # x축 선 없애기 + panel.grid.minor.x = element_blank(), + panel.grid.major.y = element_line(colour="grey90", linetype="dashed")) + + ggtitle("Cleveland dot plot of Max.Price of Models with different shape by Type")
다음으로, Type(Large, Midsize, Small) 별로 facet_grid(Type ~ ., scales="free_y", space="free_y") 을 적용하여 면을 분할을 한 클리브랜드 점 그래프(Cleveland dot plot)을 그려보겠습니다.
면 분할해서 그리려면 위의 예처럼 ggplot2 내 aes(reorder)로는 안되구요, 먼저 Type과 Max.Price 순서대로 데이터셋을 따로 정렬해서 요인(factor)으로 levels 를 지정해서 변환해주어야 합니다. 그래프는 상대적으로 쉬운데, 데이터셋 정렬/요인변환이 어려울 수 있겠습니다.
> # Type, Max.Price 순서대로 정렬 > Model_Order <- Cars93_P$Model[order(Cars93_P$Type, # Large, Midsize, Small 순서 + -Cars93_P$Max.Price, # 높은것에서 낮은 순서 + decreasing=TRUE)] > > # Model_Order를 요인(factor)으로 변환 > Cars93_P$Model <- factor(Cars93_P$Model, levels=Model_Order) > > # Type별로 면 분할, Max.Price 순서대로 정렬된 Cleveland dot plot > ggplot(Cars93_P, aes(x = Max.Price, y = Model)) + + geom_point(size = 3, aes(colour = Type)) + + theme_bw() + + theme(panel.grid.major.y = element_blank(), + panel.grid.minor.y = element_blank()) + + facet_grid(Type ~ ., scales="free_y", space="free_y") + + ggtitle("Cleveland dot plot of Max.Price of Models with Facets of Type")
다음으로, 차종(Type)별로 면 분할은 유지하면서 위의 Max.Price 에 더해서 Min.Price 를 추가하고 모양(shape)을 다르게 제시해보겠습니다.
이것도 데이터셋을 따로 미리 손을 봐줘야 합니다. reshape 패키지의 melt() 함수를 사용해서 Max.Price, Min.Price 두 값을 Price_cd (Max.Price, Min.Price)와 Price (value) 의 두개 변수로 녹여서 데이터 구조를 ggplot2의 geom_point()에 사용할 수 있도록 변경하여야 합니다. (reshape 패키지의 melt(), cast() 함수는 여기서 자세히 설명하기가 힘든데요, 따로 알아보시면 좋겠습니다)
> #-------- > # Min.Price 추가 > # melt > library(reshape) > Cars93_P_melt <- melt(Cars93_P, idvars = c("Type", "Model")) Using Model, Type as id variables > head(Cars93_P_melt) Model Type variable value 1 Integra Small Min.Price 12.9 2 Legend Midsize Min.Price 29.2 3 100 Midsize Min.Price 30.8 4 535i Midsize Min.Price 23.7 5 Century Midsize Min.Price 14.2 6 LeSabre Large Min.Price 19.9 > > # 변수명 변경 > Cars93_P_melt <- rename(Cars93_P_melt, c(variable = "Price_cd", value = "Price")) > head(Cars93_P_melt) Model Type Price_cd Price 1 Integra Small Min.Price 12.9 2 Legend Midsize Min.Price 29.2 3 100 Midsize Min.Price 30.8 4 535i Midsize Min.Price 23.7 5 Century Midsize Min.Price 14.2 6 LeSabre Large Min.Price 19.9 > > # Type별로 면 분할, Max.Price 순서대로 정렬, Min.Price추가된 Cleveland dot plot > ggplot(Cars93_P_melt, aes(x = Price, y = Model)) + + geom_segment(aes(yend=Model, xend=0)) + # 점까지만 선 그리기 + geom_point(size=3, aes(shape = Price_cd)) + # Price_cd로 모양 구분 + theme_bw() + # backgroud 색 없애기 + theme(panel.grid.major.y = element_blank(), # y축 없애기 + panel.grid.minor.y = element_blank()) + # y축 없애기 + facet_grid(Type ~ ., scales="free_y", space="free_y") + # Type별로 면 분할 + ggtitle("Cleveland dot plot of Max, Min Price of Models with Facets of Type")
위의 세번째 그래프처럼 Max.Price와 Min.Price를 같은 그래프에 그리는데, 만약 이것을 막대 그래프로 그린다고 상상해 보세요. 막대그래프로 그린다면 지저분하고 해석, 가독성이 클리브랜드 점 그래프 대비 떨어질겁니다.
Python 의 Plotly 모듈을 사용해서 클리브랜드 점 그래프 (Cleveland Dot Plot in Python using Plotly) 그리는 방법은 https://rfriend.tistory.com/802 를 참고하세요.
[Reference]
Cleveland, William S. 1984. “Graphical Methods for Data Presentation: Full Scale Breaks, Dot Charts, and Multibased Logging.” The American Statistician, 38:270-280.
Dot Plots: A Useful Alternative to Bar Charts, Naomi B. Robbins, Ph.D. March 7, 2006
이제 이차원 밀도 그래프 (2D Density Plot)을 그려보겠습니다. 그리고 5월과 7월달의 Month를 색깔로 구분하여 보겠습니다.
이때 조심해야 할 것이 있습니다. aes() 에 shape이나 colour 에는 범주형변수(factor)가 들어가야 합니다. 만약 연속형 변수가 들어가면 "Error: A continuous variable can not be mapped to shape" 라는 에러 메시지가 뜹니다.
> # 2차원 밀도 그래프 : 모양과 색깔로 구분
> # 연속형 변수라서 error
> ggplot(data=airquality_May_July, aes(x=Wind, y=Temp, shape=Month)) +
+ geom_point() +
+ stat_density2d() +
+ ggtitle("2D desity plot of Wind and Tmep, at May and July")
Error: A continuous variable can not be mapped to shape
Month를 Month.ch라는 새로운 문자형 변수로 변환해, 이를 사용해서 이차원 밀도 그래프를 Month별로 모양과 색깔을 구분해서 그려보겠습니다.
stat_density2d() 함수로 커널 밀도 추정치를 계산해서 2차원 밀도 그래프를 그리면,
> # 2차원 밀도 그래프 : Month를 모양으로 구분
> ggplot(data=airquality_May_July, aes(x=Wind, y=Temp, shape=Month.ch)) +
+ geom_point(size=4) +
+ stat_density2d() +
+ ggtitle("2D desity plot of Wind and Tmep, May/July by Shape")
>
> # 2차원 밀도 그래프 : Month를 색깔로 구분
> ggplot(data=airquality_May_July, aes(x=Wind, y=Temp, colour=Month.ch)) +
+ geom_point(size=4) +
+ stat_density2d() +
+ ggtitle("2D desity plot of Wind and Tmep, at May/July by Colour")
이번에는 (범례가 있기는 합니다만) 사용자의 가독성을 조금 더 높여주기 위해 2차원 밀도 그래프의 5월, 7월 두 집단의 중앙 부위에 년/월을 annotate()의 "text"로 라벨을 추가해 보겠습니다.
> # 2차원 밀도 그래프 : Month를 색깔로 구분, 년/월 라벨 추가
> ggplot(data=airquality_May_July, aes(x=Wind, y=Temp, colour=Month.ch)) +
+ geom_point(size=4) +
+ stat_density2d() +
+ ggtitle("2D desity plot of Wind and Tmep, at1973. May/July by Colour") +
+ annotate("text", x=11, y=65, label="1973.May", alpha=0.5) +
+ annotate("text", x=9, y= 83, label="1973.July", alpha=0.5)