plotly + ggplot2plotlyplotly.js는 plot.ly와 Dash를 배경에 두고 개발된 오픈소스 자바스크립트 라이브러리로 R로 가져온 인터랙티브 시각화 팩키지는 plotly는 웹페이지 Plotly R Open Source Graphing Library에서 다양한 예제를 만나볼 수 있고, Plotly ggplot2 Library를 통해서 영감을 얻을 수 있다. An interactive graphing library for R를 공식적인 GitHub 개발 사이트로 알려져 있다.
rbokeh 인터랙티브 데이터 시각화 팩키지와 비교하여 plotly의 장점은 ggplot2와 연계가 된다는 점이 강점이다. 즉, plotly를 통해서 정적 ggplot2 시각화 산출물을 명령어 하나로 인터랙티브 시각화 산출물로 수월하게 탈바꿈시킬 수 있다.
즉, 정적 ggplot 그래프 객체를 생성시킨 후에 ggplotly() 함수에 던지게 되면 나름 유용한 인터랙티브 시각화 그래프 산출물이 생성된다.
library(tidyverse)
library(plotly)
library(gapminder)
## `ggplot` 정적 그래프
hello_world_g <- gapminder %>%
filter(year == max(year)) %>%
ggplot(aes(x=gdpPercap, y=lifeExp, color=continent)) +
geom_point()
hello_world_g## `plotyly` 인터랙티브 그래프
ggplotly(hello_world_g)각 대륙별로 속한 국가수를 가장 최근 연도를 기준으로 살펴보자. 이를 위해서 먼저 가장 최근 조사연도를 추출하고 각 대륙별로 국가수를 계수한다. 그리고 나서 plot_ly() 함수에 던지는데 변수를 식별하는데 ~를 사용하는 것이 plotly 팩키지를 사용할 때 다른 rbokeh 혹은 ggplot2와 차이가 난다. ggplot2 문법과 마찬가지로 geom_col()와 유사하게 add_bars()를 사용해서 막대그래프를 완성하게 된다.
gapminder %>%
filter(year == max(year)) %>%
count(continent) %>%
mutate(continent = fct_reorder(continent, n, .desc=TRUE)) %>%
plot_ly(x = ~continent, y = ~n) %>%
add_bars()기대수명(lifeExp)은 돈(gdpPercap)보다 소중하기 때문에 가장 최근연도 기대수명 산포를 add_histogram() 함수를 통해서 시각화한다. 최대 bin 갯수를 nbinsx=로 설정하여 히스토그램을 제작할 수 있다.
gapminder %>%
filter(year == max(year)) %>%
plot_ly(x = ~lifeExp) %>%
add_histogram(nbinsx = 30)혹은 xbins=를 통해 구간을 설정하여 35세를 기준으로 5세 간격으로 히스토그램 생성도 가능하다.
gapminder %>%
filter(year == max(year)) %>%
plot_ly(x = ~lifeExp) %>%
add_histogram(xbins = list(start = 35, end = 85, size = 5))밀도는 선으로 표현되기 때문에 add_lines()를 사용한다. 각 대륙별로 데이터프레임을 생성시키고, 밀도를 density()로 추정한다. 그리고 나서 plot_ly()에 기대수명 밀도에 색상을 부여한다.
gapminder_df <- gapminder %>%
filter(year == max(year))
## 대륙별 데이터프레임 -----
africa_df <- gapminder_df %>% filter(continent == "Africa")
asia_df <- gapminder_df %>% filter(continent == "Asia")
europe_df <- gapminder_df %>% filter(continent == "Europe")
## 밀도 추정 -----
africa_den <- density(africa_df$lifeExp)
asia_den <- density(asia_df$lifeExp)
europe_den <- density(europe_df$lifeExp)
## 시각화 -----
plot_ly(opacity = 1) %>%
add_lines(x = ~africa_den$x, y = ~africa_den$y, name = "아프리카") %>%
add_lines(x = ~asia_den$x, y = ~asia_den$y, name = "아시아") %>%
add_lines(x = ~europe_den$x, y = ~europe_den$y, name = "유럽") %>%
layout(xaxis = list(title = '기대수명'),
yaxis = list(title = '밀도'))x 변수도 연속형이고, y 변수도 연속형인 경우 인터랙티브 산점도를 add_markers() 함수로 구현한다.
gapminder %>%
filter(year == max(year)) %>%
plot_ly(x = ~gdpPercap, y = ~lifeExp) %>%
add_markers()add_bars() 막대그래프는 기본디폴트 설정으로 barmode = "dodge"로 되어 있어 이를 쌓고자 하는 경우 layout(barmode = "stack")으로 추가 설정을 한다.
gapminder %>%
count(year, continent) %>%
plot_ly(x = ~year, y = ~n, color = ~continent) %>%
add_bars() %>%
layout(barmode = "stack")비율로 변환시킬 경우 비율을 구한 후에 계산된 비율을 plot_ly()에 전달한다.
gapminder %>%
count(year, continent) %>%
group_by(year) %>%
mutate(`비율` = n / sum(n)) %>%
plot_ly(x = ~year, y = ~`비율`, color = ~continent) %>%
add_bars() %>%
layout(barmode = "stack")add_boxplot() 함수를 사용하게 되면 대륙별로 상자그림을 통해 기대수명 분포를 한눈에 파악할 수 있다.
gapminder %>%
filter(year == max(year)) %>%
plot_ly(x = ~continent, y = ~lifeExp, color = ~continent) %>%
add_boxplot()rbokeh와 마찬가지로 plotly도 색상(color), 투명도(opacity), 모양(symbol), 크기(size), 폭(width) 등을 지정할 수 있다.
투명도(opacity =), 모양(symbol =), 크기(size =)를 지정할 수 있다.
gapminder %>%
filter(year == max(year)) %>%
plot_ly(x = ~gdpPercap, y = ~lifeExp, color = ~continent) %>%
add_markers(marker = list(opacity = 0.5, symbol = "square", size=20))RColorBrewer 팩키지가 내장되되어 있어 add_markers() 함수의 colors =인자에 팔레트를 사용하는 것도 가능하고 색상을 각 범주별로 지정하는 것도 가능하다.
gapminder %>%
filter(year == max(year)) %>%
plot_ly(x = ~gdpPercap, y = ~lifeExp, color = ~continent) %>%
add_markers(colors = "Dark2")layout() 함수에 title=을 통해 그래프 제목을 달 수도 있고 xaxis =, yaxis =에 축라벨을 붙이는 것도 가능하다. showgrid=FALSE를 통해 참조선도 보여주거나 감출 수 있다.
gapminder %>%
filter(year == max(year)) %>%
plot_ly(x = ~gdpPercap, y = ~lifeExp, color = ~continent) %>%
add_markers(colors = c("orange", "darkgray", "skyblue", "black", "red")) %>%
layout(title = '1인당 GDP와 기대수명 관계',
xaxis = list(title = '1인당 GDP',
zeroline = TRUE,
range = c(0, 50000)),
yaxis = list(title = '기대수명',
range = c(0,85),
showgrid = FALSE))tooltiphoverinfo = "text"를 사용해서 text에 마우스로 점 주변을 선회(hover)시킬 때 표식에 제공할 내용을 정리한다.
gapminder %>%
filter(year == max(year)) %>%
plot_ly(x = ~gdpPercap, y = ~lifeExp, color = ~continent, hoverinfo = "text",
text = ~paste0("<b>", "Gapminder", "</b> <br>",
"인당 GDP: ", gdpPercap, "<br>",
"기대수명: ", lifeExp)) %>%
add_markers(colors = c("orange", "darkgray", "skyblue", "black", "red")) %>%
layout(title = '1인당 GDP와 기대수명 관계',
xaxis = list(title = '1인당 GDP',
zeroline = TRUE,
range = c(0, 50000)),
yaxis = list(title = '기대수명',
range = c(0,85)))회귀선을 비롯한 모형 적합선을 add_lines() 명령어를 통해서 추가할 수 있다. showlegend = FALSE를 통해 모형적합선에 대한 범례를 추가시킬 수 있다.
gap_loess <- loess(lifeExp ~ gdpPercap, data = gapminder_df)
gap_lm <- lm(lifeExp ~ gdpPercap, data = gapminder_df)
gapminder_df %>%
plot_ly(x = ~gdpPercap, y = ~lifeExp, hoverinfo = "text",
text = ~paste0("<b>", "Gapminder", "</b> <br>",
"인당 GDP: ", gdpPercap, "<br>",
"기대수명: ", lifeExp)) %>%
add_markers(colors = c("orange", "darkgray", "skyblue", "black", "red"), showlegend = FALSE) %>%
add_lines(y = ~fitted(gap_lm), name = "회귀선") %>%
add_lines(y = ~fitted(gap_loess), name = "LOESS") # layout(showlegend = FALSE)subplot으로 병합subplot() 함수로 서로 다른 형태 plotly 객체를 하나로 모아 작성할 수 있다.
asia_plotly <- gapminder_df %>%
filter(continent == "Asia") %>%
plot_ly(x = ~gdpPercap, y = ~lifeExp, hoverinfo = "text",
text = ~paste0("<b>", "Gapminder", "</b> <br>",
"인당 GDP: ", gdpPercap, "<br>",
"기대수명: ", lifeExp)) %>%
add_markers(name = ~continent) %>%
layout(title = '아시아 인당 GDP와 기대수명',
xaxis = list(title = '1인당 GDP'),
yaxis = list(title = '기대수명'))
africa_plotly <- gapminder_df %>%
filter(continent == "Africa") %>%
plot_ly(x = ~gdpPercap, y = ~lifeExp, hoverinfo = "text",
text = ~paste0("<b>", "Gapminder", "</b> <br>",
"인당 GDP: ", gdpPercap, "<br>",
"기대수명: ", lifeExp)) %>%
add_markers(name = ~continent) %>%
layout(title = '아프리카 인당 GDP와 기대수명',
xaxis = list(title = '1인당 GDP'),
yaxis = list(title = '기대수명'))
subplot(asia_plotly, africa_plotly, nrows = 1, shareY = TRUE, shareX = TRUE)group_by() + do() 조합group_by()가 split() 함수와 유사한 기능을 제공하여 각 대륙별로 데이터프레임을 쪼개고 do() 명령어가 lapply() 함수와 동일하게 시각화를 각 대륙별 작업을 담당하게 되고 이를 subplot() 함수로 최종 조합하여 시각화 결과물을 산출시키게 된다.
gapminder_df %>%
group_by(continent) %>%
do(plot = plot_ly(data =., x = ~gdpPercap, y = ~lifeExp, hoverinfo = "text",
text = ~paste0("<b>", "Gapminder", "</b> <br>",
"인당 GDP: ", gdpPercap, "<br>",
"기대수명: ", lifeExp)) %>%
add_markers(name = ~continent) %>%
layout(title = '인당 GDP와 기대수명',
xaxis = list(title = '1인당 GDP'),
yaxis = list(title = '기대수명'))
) %>%
subplot(nrows = 2)산점도 행렬은 1975년 John Hartigan이 제안한 방식으로 산점도를 행렬형태 다수 작은 창으로 시각화하고 인터랙티브 방식으로 작은 창에 연결된 관계를 시각적으로 확인할 수 있도록 한다. plot_ly() 함수 다음에 add_trace()를 추가하고 dimensions =에 관찰하고자 하는 변수를 추가하면 수월히 구현할 수 있다. 마지막에 style()을 통해 중복되는 행렬창을 제거할 수 있다.
gapminder_df %>%
mutate(log_pop = log10(pop)) %>%
plot_ly(color = ~continent) %>%
add_trace(
type = 'splom',
dimensions = list(
list(label='기대수명', values = ~lifeExp),
list(label='인구수', values = ~log_pop),
list(label='인당GDP', values = ~gdpPercap)
)
) %>%
style(showlowerhalf = FALSE)적외선 열지도(heatmap)와 유사하게 두연속형 변수로 산점도를 그릴 경우 너무 많은 점이 특정 지역에 집중되는 경우 “2D 히스토그램” 혹은 “적외선 열지도(heatmap)”를 통해 시각화하는 것이 많이 사용된다. 이를 위해서 add_histogram2d() 함수를 활용한다.
gapminder_df %>%
plot_ly(x = ~gdpPercap, y = ~lifeExp) %>%
add_histogram2d(nbinsx= 30, nbinsy=30)airports <- read_csv("https://raw.githubusercontent.com/datasets/airport-codes/master/data/airport-codes.csv")
airport_df <- airports %>%
select(ident, name, iso_country, municipality, coordinates) %>%
separate(coordinates, into=c("lat", "long"), sep = ",") %>%
mutate(long = as.numeric(long),
lat = as.numeric(lat)) %>%
filter(iso_country == "KR") %>%
mutate(value = rpois(1374, lambda=100))
map_data(database = 'world', regions = 'south korea') %>%
group_by(group) %>%
plot_geo(x = ~long, y = ~lat) %>%
add_markers(size = I(1))