ggplot2 dual axis
ggplot2
의 이중축
ggplot2
의 scale_y_continuous(sec.axis = sec_axis(~.))
을 활용하면, 다음과 같은 그림을 그릴 수 있습니다.
어떤 주식의 주가를 나타내고 있는 듯 한데, 거래량은 별다른 패턴이 없어 보이고, 가격은 우상향하여 두 달만에 2배 가까이 오르는 바람직한 그래프입니다.
이제 위의 그래프를 ggplot2
의 sec.axis = sec_axis()
를 활용하여 그려봅시다.
데이터
데이터는 다음과 같습니다. 가격은 평균 1000, 800, 600으로 하향하고 있고, 거래량은 100에서 200으로 뛰었습니다.
n = 90
price <- c(rnorm(n/3, 1000, 50),
rnorm(n/3, 800, 50),
rnorm(n/3, 600, 50))
xdate <- seq(from = as.Date('2020-01-01'),
to = as.Date('2020-03-01'),
along.with = price)
volume <- c(rnorm(n/2, 100, 10),
rnorm(n/2, 200, 10))
head(price)
## [1] 957.3960 1056.5378 963.9979 1004.5250 1073.5585 977.7241
head(xdate)
## [1] "2020-01-01" "2020-01-01" "2020-01-02" "2020-01-03" "2020-01-03" "2020-01-04"
head(volume)
## [1] 108.50670 95.80234 107.41140 85.94745 88.82841 112.11918
dat <- data.frame(date=xdate, price=price, vol=volume)
head(dat)
## date price vol ## 1 2020-01-01 957.3960 108.50670 ## 2 2020-01-01 1056.5378 95.80234 ## 3 2020-01-02 963.9979 107.41140 ## 4 2020-01-03 1004.5250 85.94745 ## 5 2020-01-03 1073.5585 88.82841 ## 6 2020-01-04 977.7241 112.11918
그래프로 그려 보면 다음과 같습니다.
library(ggplot2)
ggplot(dat, aes(x=date, y=price, size=vol)) +
geom_point() +
geom_line(size=1)
이중축을 위한 변환
ggplot2
의 sec.axis=
는 기본적으로 동일한 변수에 대해 변환한 값을 표기하기 위한 함수입니다.
하지만 두 변수를 적절히 변환하여, 두 변수에 대해 각각의 축을 나타내는 데에 사용할 수도 있습니다.
이때 변환은 직접 계산할 수도 있고, 다음과 같은 함수를 만들어 줄 수도 있습니다.
genTransformation = function(dat) {
list(
volToPrice = function(x) {
diff(range(dat$price, na.rm=TRUE))*(x-min(dat$vol))/
diff(range(dat$vol, na.rm=TRUE)) + min(dat$price)
},
priceToVol = function(x) {
(x-min(dat$price)) * diff(range(dat$vol, na.rm=TRUE)) /
diff(range(dat$price, na.rm=TRUE)) + min(dat$vol)
})
}
위의 함수를 실행하면 반환값으로 두 함수를 가지고 있는 리스트가 반환됩니다. price
를 vol
의 스케일로 변환하고, 그 반대로 변환하는 함수입니다.
다음에 두 함수를 연달아 적용하면 항등 함수가 됨을 알 수 있습니다.
tr <- genTransformation(dat)
#dat$price == tr[["volToPrice"]](tr[["priceToVol"]](dat$price))
near(dat$price, tr[["volToPrice"]](tr[["priceToVol"]](dat$price)))
## [1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE ## [17] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE ## [33] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE ## [49] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE ## [65] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE ## [81] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
scale_y_continuous(sec.axis = sec_axis(~.))
다음은 위에서 얻은 변환 함수와 scale_y_continuous(sec.axis = sec_axis(~.))
를 활용하여 이중축을 만드는 과정을 보여줍니다. 편의를 위해 축의 색도 바꾸었습니다.
require(tidyr)
dat2 <- gather(dat, "key", "value", price, vol)
library(dplyr)
dat31 <- dat2 %>% filter(key=='price')
dat32 <- dat2 %>% filter(key=='vol') %>%
mutate(value=tr[["volToPrice"]](value))
dat4 <- bind_rows(dat31, dat32)
# Default palette of ggplot2
# https://stackoverflow.com/questions/8197559/emulate-ggplot2-default-color-palette
gg_color_hue <- function(n) {
hues = seq(15, 375, length = n + 1)
hcl(h = hues, l = 65, c = 100)[1:n]
}
cols = gg_color_hue(2)
ggplot(dat4, aes(x=date, y=value, col=key)) +
geom_point() +
geom_line() +
scale_y_continuous(sec.axis = sec_axis(~ tr[["priceToVol"]](.),
name='volume'),
name = 'price') +
theme(axis.title.y.left = element_text(color=cols[1]),
axis.text.y.left = element_text(color=cols[1]),
axis.title.y.right = element_text(color=cols[2]),
axis.text.y.right = element_text(color=cols[2])) +
guides(col='none')
- 참고: StackOverflow 질문
Leave a comment