1. 샤이니 입문하기 CP 9
1) 샤이니 기본 구조
#
# 01
# 샤이니 기본 구조
# install.packages("shiny")
library(shiny)
# ui
ui <- fluidPage("user interface")
# server
server <- function(input, output, session){}
# shinyApp
shinyApp(ui, server)
#
2) 샘플 실행
# 02
# 샤이니 샘플
library(shiny)
# 샘플 보기
runExample()
# "01_hello" 샘플 보기
runExample("01_hello")
# 샘플의 데이터 = 올드 페이스풀 간헐천
head(faithful)
# eruptions: 분출 시간
# waiting: 다음 분출 때까지 대기 시간
#
# "02_text" 샘플 보기
runExample("02_text")
#
3) 01_Hello 샘플 만들기
# 03
# "01_hello" 샘플 만들기
library(shiny)
# ui
ui <- fluidPage(
titlePanel("Number 1 sample"),
sidebarLayout(
sidebarPanel(
sliderInput(inputId = "bins", # server의 input$bins 로 전달
label = "Number of bins",
min = 1, max = 50,
value = 15)
),
mainPanel(
plotOutput(outputId = "histplot") # 수정된 결과 output$histplot 을 ui에 출력
)
)
)
# server
server <- function(input, output, session){
# 수정된 결과가 output$histplot 으로 저장
output$histplot <- renderPlot({
x <- faithful$waiting
# length.out = 구간의 수 + 1
bins <- seq(min(x), max(x), length.out = input$bins+1) # 입력받은 값으로 결과 수정
hist(x, breaks = bins,
col = "skyblue", border = "black",
xlab = "Waiting (min)",
main = "Histogram of waiting")
})
}
# shinyApp
shinyApp(ui, server)
#
4) 입력 받기 _ input
# 04
# 연비를 입력하는 화면 만들기 => ui 만들기 실습
library(shiny)
# ui
ui <- fluidPage(
sliderInput(inputId = "range",
label = "Fuel efficiency",
min = 0, max = 35,
value = c(0, 10))
)
# server
server <- function(input, output, session){}
# shinyApp
shinyApp(ui, server)
#
5) 출력 하기 _ out put
# 05
# 연비를 입력해서 범위 값을 출력
library(shiny)
# ui
ui <- fluidPage(
sliderInput(inputId = "range",
label = "Fuel efficiency",
min = 0, max = 35,
value = c(0, 10)),
# 범위 값 출력하는 화면
textOutput("value")
)
# server
server <- function(input, output, session){
output$value <- renderText(input$range[2] - input$range[1])
}
# shinyApp
shinyApp(ui, server)
#
6) 입출력 과정에서의 렌더링 함수의 중요성
# 06
# 연비를 입력해서 범위 값을 출력 오류가 있는 내용
# 렌더링 함수의 중요성
library(shiny)
# ui
ui <- fluidPage(
sliderInput(inputId = "range",
label = "Fuel efficiency",
min = 0, max = 35,
value = c(0, 10)),
# 범위 값 출력하는 화면
textOutput("value")
)
# server
server <- function(input, output, session){
# renderText 함수 사용하지 않고 출력
# 렌더링 함수를 사용해야 서버와 ui를 연결시켜줄 수 있음
output$value <- (input$range[2] - input$range[1])
}
# shinyApp
shinyApp(ui, server)
#
output$value <- (input$range[2] - input$range[1])
이 코드가 아래의 코드로 바뀌어야 함
output$value <- renderText(input$range[2] - input$range[1])
7) 반응식의 도입
# 07
# 연비를 입력해서 결과를 출력하는 화면 만들기
# 연비의 범위값에 해당하는 자동차 데이터를 출력
library(shiny)
# install.packages("DT")
library(DT)
library(ggplot2)
mpg <- mpg
# ui
ui <- fluidPage(
sliderInput(inputId = "range",
label = "Fuel efficiency",
min = 0, max = 35,
value = c(0, 10)),
dataTableOutput("table")
)
# server
server <- function(input, output, session){
# 반응식 = reactive()
cty_sel = reactive({
cty_sel = subset(mpg, cty >= input$range[1] & cty <= input$range[2])
return(cty_sel)
})
output$table <- renderDataTable(cty_sel())
}
# shinyApp
shinyApp(ui, server)
#
8) 레이아웃 적용
# 레이아웃 설정
library(shiny)
# ui
ui <- fluidPage(
fluidRow(
# div(style =): html
column(width = 9, div(style = "height:450px;
border: 4px solid red;"), "Width 9"),
column(width = 3, div(style = "height:450px;
border: 4px solid blue;"), "Width 3"),
column(width = 12, div(style = "height:450px;
border: 4px solid yellow;"), "Width 12")
)
)
# server
server <- function(input, output, session){}
# shinyApp
shinyApp(ui, server)
#
2. 데이터 분석 어플리케이션 개발하기 CP 10
1) 라이브러리, 데이터 불러오기 : 반응형 지도 만들기
#
#
# 10_1
# 반응형 지도 만들기
# 7장 내용 기반
# 라이브러리
# install.packages("mapedit")
library(sf);library(leaflet);library(tidyverse);library(shiny);library(mapedit);library(DT)
# 데이터 불러오기
# 아파트 가격
load("./data/apt_price.rdata")
head(apt_price)
# 서울시 그리드 데이터
grid <- st_read("./data/sigun_grid/seoul.shp")
# 서울시 경계선 데이터
bnd <- st_read("./data/sigun_bnd/seoul.shp")
# 최고가 레스터 데이터
load("./data/raster_high.rdata")
raster_high
# 급등 지역 레스터 데이터
load("./data/raster_hot.rdata")
실거래, 경계선 데이터, 최고가 지역, 급등 지역, 그리드 데이터 불러오기
2) 마커 클러스터링 설정 : 반응형 지도 만들기
#
# 마커 클러스터링 옵션 설정
# 상위 10%, 하위 10%, 나머지
q10 <- quantile(apt_price$py, probs = seq(.1, .9, by = .1))
# 상위 10% = 90%
pct_90 <- as.numeric(q10[9])
# 하위 10% = 10%
pct_10 <- as.numeric(q10[1])
# 마커 클러스터링 함수 불러오기
load("./data/circle_marker/circle_marker.rdata")
# 색상 설정
circle.colors <- c()
데이터 왜곡을 방지하기 위해 하위 10%, 상위 10%를 지정함.
그 후 등급별 차이를 직관적으로 보여줄 수 있게 마커에 표시할 색상을 circle.colors <- c(" ", " ", " ") 에서 설정.
3) 반응형 지도 만들기 : 반응형 지도 만들기
# 반응형 지도 만들기
leaflet() %>%
addTiles(options = providerTileOptions(minZoom = 9, maxZoom = 18)) %>%
# 서울시 경계선
addPolygons(data = bnd,
color = "gold",
fill = NA,
weight = 5) %>%
# 최고가 레스터 데이터
addRasterImage(raster_high,
colors = colorNumeric(palette = c("blue","green","yellow","red"),
domain = values(raster_high),
na.color = "transparent"),
opacity = 0.4) %>%
# 급등 지역 레스터 데이터
addRasterImage(raster_hot,
colors = colorNumeric(palette = c("blue", "green", "yellow", "red"),
domain = values(raster_hot),
na.color = "transparent"),
opacity = 0.4) %>%
# 체크 박스
addLayersControl(baseGroups = c("High Price in 2021", "Hot Price in 2021"),
options = layersControlOptions(collapsed = F)) %>%
# 마커 클러스터링
addCircleMarkers(data = apt_price,
# 경도
lng = unlist(map(apt_price$geometry,1)),
# 위도
lat = unlist(map(apt_price$geometry,2)),
fillColor = circle.colors,
weight = apt_price$py,
clusterOptions = markerClusterOptions(iconCreateFunction=JS(avg.formula)))
#
4) 데이터 불러오기부터 그리드 필터링까지 : 지도 애플리케이션 만들기
# 10_2
# 지도 애플리케이션 만들기
# 그리드 추가
# 라이브러리
library(sf);library(leaflet);library(tidyverse);library(shiny);library(mapedit);library(DT)
library(leafem)
# 데이터 불러오기
# 아파트 가격
load("./data/apt_price.rdata")
head(apt_price)
# 서울시 그리드 데이터
grid <- st_read("./data/sigun_grid/seoul.shp")
# 서울시 경계선 데이터
bnd <- st_read("./data/sigun_bnd/seoul.shp")
# 최고가 레스터 데이터
load("./data/raster_high.rdata")
raster_high
# 급등 지역 레스터 데이터
load("./data/raster_hot.rdata")
raster_hot
#
# 그리드 데이터 sf형을 sp형으로 변환
grid <- as(grid, "Spatial")
# sfg: simple feature geometry
# sfc: simple feature columns (the coordinate)
# sf: simple feature columns + attribute (data.frame)
# 그리드 데이터를 sfc로 변환
grid <- as(grid, "sfc")
grid
# 아파트 가격 데이터와 그리드 데이터 합치기
# 데이터가 있는 그리드만 추출
grid <- grid[which(sapply(st_contains(st_sf(grid), apt_price),length) > 0)]
# 그리드 확인
plot(grid)
5) 파이프라인으로 마커클러스터링~그리드 추가해서 반응형 지도 모듈화하기 : 지도 애플리케이션 만들기
#
# 마커 클러스터링 옵션 설정
# 상위 10%, 하위 10%, 나머지
q10 <- quantile(apt_price$py, probs = seq(.1, .9, by = .1))
# 상위 10% = 90%
pct_90 <- as.numeric(q10[9])
# 하위 10% = 10%
pct_10 <- as.numeric(q10[1])
# 마커 클러스터링 함수 불러오기
load("./data/circle_marker/circle_marker.rdata")
# 색상 설정
circle.colors <- c()
#
# 반응형 지도 만들기
m <- leaflet() %>%
addTiles(options = providerTileOptions(minZoom = 9, maxZoom = 18)) %>%
# 서울시 경계선
addPolygons(data = bnd,
color = "gold",
fill = NA,
weight = 5) %>%
# 최고가 레스터 데이터
addRasterImage(raster_high,
colors = colorNumeric(palette = c("blue","green","yellow","red"),
domain = values(raster_high),
na.color = "transparent"),
opacity = 0.4) %>%
# 급등 지역 레스터 데이터
addRasterImage(raster_hot,
colors = colorNumeric(palette = c("blue", "green", "yellow", "red"),
domain = values(raster_hot),
na.color = "transparent"),
opacity = 0.4) %>%
# 체크 박스
addLayersControl(baseGroups = c("High Price in 2021", "Hot Price in 2021"),
options = layersControlOptions(collapsed = F)) %>%
# 마커 클러스터링
addCircleMarkers(data = apt_price,
# 경도
lng = unlist(map(apt_price$geometry,1)),
# 위도
lat = unlist(map(apt_price$geometry,2)),
fillColor = circle.colors,
weight = apt_price$py,
clusterOptions = markerClusterOptions(iconCreateFunction=JS(avg.formula))) %>%
# 그리드 추가
addFeatures(st_sf(grid), layerId = ~seq_len(length(grid)), color = "gray")
#
6) 렌더링 함수 없이 실행하기 : 지도 애플리케이션 만들기
# 0310_app_3
# 그리드 선택할 수 있는 지도 웹 어플리케이션 만들기
# 렌더링 함수 없이 실습하여 확인
# 라이브러리
library(sf);library(leaflet);library(tidyverse);library(shiny);library(mapedit);library(DT);library(leafem)
# ui
ui <- fluidPage(
# 그리드 선택 모듈
selectModUI("selectmap"),
"No response"
)
# server
server <- function(input, output, session){
callModule(selectMod, "selectmap", m)
}
# shinyApp
shinyApp(ui, server)
#
7) 그리드 선택할 수 있는 어플리케이션 구현하기 : 지도 애플리케이션 만들기
# 그리드 선택할 수 있는 지도 웹 어플리케이션 만들기
# 렌더링 함수 없이 실습하여 확인
# 라이브러리
library(sf);library(leaflet);library(tidyverse);library(shiny);library(mapedit);library(DT);library(leafem)
# ui
ui <- fluidPage(
# 그리드 선택 모듈
selectModUI("selectmap"),
"No response"
)
# server
server <- function(input, output, session){
callModule(selectMod, "selectmap", m)
}
# shinyApp
shinyApp(ui, server)
#
3. 데이터 분석 어플리케이션 개발하기 CP 10 (0313 지난 시간 이어서)
1) 지난 시간 이어서 -> 라이브러리~클러스터링 함수까지 : 지도 애플리케이션 만들기
# 배포판 작성
# 10_1, 10_2, 10_3, 10_4, 10_5 종합적으로 작성 # 7장 내용 기반
# 반응형 지도 만들기
# 라이브러리
library(sp);library(sf);library(leaflet);library(tidyverse);library(raster);library(rgdal);library(tmap);library(mapedit);library(leafem);library(ggfortify);library(grid);library(shiny);library(DT)
# 2. 데이터 불러오기
# 아파트 가격
load("./data/apt_price.rdata")
# 서울시 그리드 데이터
grid <- st_read("./data/sigun_grid/seoul.shp")
# 서울시 경계선 데이터
bnd <- st_read("./data/sigun_bnd/seoul.shp")
# 최고가 레스터 데이터
load("./data/raster_high.rdata")
# 급등 지역 레스터 데이터
load("./data/raster_hot.rdata")
# 3. 그리드 데이터 전처리
# 그리드 데이터 sf형을 sp형으로 변환
grid <- as(grid, "Spatial")
# sfg: simple feature geometry
# sfc: simple feature columns (the coordinate)
# sf: simple feature columns + attribute (data.frame)
# 그리드 데이터를 sfc로 변환
grid <- as(grid, "sfc")
# 아파트 가격 데이터와 그리드 데이터 합치기
# 데이터가 있는 그리드만 추출
grid <- grid[which(sapply(st_contains(st_sf(grid), apt_price),length) > 0)]
# 4. 마커 클러스터
# 마커 클러스터링 옵션 설정
# 상위 10%, 하위 10%, 나머지
# q10 <- quantile(apt_price$py, probs = seq(.1, .9, by = .1))
# 상위 10% = 90%
pct_90 <- as.numeric(quantile(apt_price$py, probs = seq(.1, .9, by = .1))[9])
# 하위 10% = 10%
pct_10 <- as.numeric(quantile(apt_price$py, probs = seq(.1, .9, by = .1))[1])
# 마커 클러스터링 함수 불러오기
load("./data/circle_marker/circle_marker.rdata")
# 색상 설정
circle.colors <- c()
2) ui 설정하기
# 5. 반응형 지도 만들기 => shiny application 내부
# 6. shiny application
# ui
ui <- fluidPage(
# 상단: 좌 (반응형 지도)
column(width = 9,
selectModUI("selectmap"),
div(style = "height:40px;")),
# 상단: 우 (슬라이더-면적, 건축연도)
column(width = 3,
sliderInput(inputId = "range_area", # ID
"Area", # 제목
min = 0, max = 350, # 범위: 최소값, 최대값
value = c(0, 200)), # default 값
sliderInput(inputId = "range_con", # ID
"Construction year", # 제목
min = 1960, max = 2021, # 범위: 최소값, 최대값
value = c(2000, 2021))), # default 값
# 하단: 입력값에 따른 데이터테이블 형태로 데이터 출력
column(width = 12,
dataTableOutput(outputId = "table"),
div(style = "height:200px;"))
)
3) 반응식 설정하기
# server
server <- function(input, output, session){
# 반응식
# A: 면적과 건축연도 범위에 해당하는 데이터 추출
all <- reactive({
all <- subset(apt_price, area >= input$range_area[1] & area <= input$range_area[2] & con_year >= input$range_con[1] & con_year <= input$range_con[2])
return(all)})
4) 지도 입출력 모듈 설정하기 (서버와 이어짐)
# server
server <- function(input, output, session){
# 반응식
# A: 면적과 건축연도 범위에 해당하는 데이터 추출
all <- reactive({
all <- subset(apt_price, area >= input$range_area[1] & area <= input$range_area[2] & con_year >= input$range_con[1] & con_year <= input$range_con[2])
return(all)})
# B: 선택된 그리드 저장
sel <- callModule(selectMod, "selectmap",
leaflet() %>%
addTiles(options = providerTileOptions(minZoom = 9, maxZoom = 18)) %>%
# 서울시 경계선
addPolygons(data = bnd,
color = "gold",
fill = NA,
weight = 5) %>%
# 최고가 레스터 데이터
addRasterImage(raster_high,
colors = colorNumeric(palette = c("blue","green","yellow","red"),
domain = values(raster_high),
na.color = "transparent"),
opacity = 0.4) %>%
# 급등 지역 레스터 데이터
addRasterImage(raster_hot,
colors = colorNumeric(palette = c("blue", "green", "yellow", "red"),
domain = values(raster_hot),
na.color = "transparent"),
opacity = 0.4) %>%
# 체크 박스
addLayersControl(baseGroups = c("High Price in 2021", "Hot Price in 2021"),
options = layersControlOptions(collapsed = F)) %>%
# 마커 클러스터링
addCircleMarkers(data = apt_price,
# 경도
lng = unlist(map(apt_price$geometry,1)),
# 위도
lat = unlist(map(apt_price$geometry,2)),
fillColor = circle.colors,
weight = apt_price$py,
clusterOptions = markerClusterOptions(iconCreateFunction=JS(avg.formula))) %>%
# 그리드 추가
addFeatures(st_sf(grid), layerId = ~seq_len(length(grid)), color = "gray")
)
5) 선택에 따른 반응 결과 저장하기
# A 와 B 교집합
# 초기 반응값 저장
rv <- reactiveValues(intersect = NULL, selectgrid = NULL)
# 반응 결과 저장
observe({
# grid selected => 선택된 그리드 저장
gs <- sel()
# 선택(selected == TRUE)된 그리드 ID를 숫자형으로 변환하여 그리드 데이터에서 가져오기(sf형으로 변환)
rv$selectgrid <- st_sf(grid[as.numeric(gs[which(gs$selected == TRUE),"id"])])
# 데이터가 있는 경우
if(length(rv$selectgrid) > 0){
# A & B 교집합
rv$intersect <- st_intersects(rv$selectgrid, all())
# geometry 삭제
# rv$intersect 결과는 리스트
rv$sel <- st_drop_geometry(apt_price[unlist(rv$intersect), ])
} else{ # 데이터가 없는 경우
rv$intersect <- NULL
}
})
6) 반응 결과 렌더링 후 실행까지
# rv$sel => 데이터테이블로 저장(렌더링 함수 사용)
output$table <- DT::renderDataTable({
dplyr::select(rv$sel,
# 열 선택
ymd, addr_1, apt_nm, price, area, floor, py) %>%
arrange(desc(py))},
extensions = 'Buttons',
options = list(dom = 'Bfrtrip',
scrollY = 300,
scrollCollapse = T,
paging = T,
buttons = c('excel'))
)
}
# shinyApp
shinyApp(ui, server)
#
4. 데이터 분석 어플리케이션 개발하기 CP 10 (0313 새로운 파일로)
1) 데이터 불러오기부터 마커클러스터링까지
# 반응형 지도 만들기
# 7장 내용 기반
# 라이브러리
library(sf);library(leaflet);library(tidyverse);library(shiny);library(mapedit);library(DT)
# 데이터 불러오기
# 아파트 가격
load("./data/apt_price.rdata")
head(apt_price)
# 서울시 그리드 데이터
grid <- st_read("./data/sigun_grid/seoul.shp")
# 서울시 경계선 데이터
bnd <- st_read("./data/sigun_bnd/seoul.shp")
# 최고가 레스터 데이터
load("./data/raster_high.rdata")
raster_high
# 급등 지역 레스터 데이터
load("./data/raster_hot.rdata")
raster_hot
#
# 마커 클러스터링 옵션 설정
# 상위 10%, 하위 10%, 나머지
q10 <- quantile(apt_price$py, probs = seq(.1, .9, by = .1))
# 상위 10% = 90%
pct_90 <- as.numeric(q10[9])
# 하위 10% = 10%
pct_10 <- as.numeric(q10[1])
# 마커 클러스터링 함수 불러오기
load("./data/circle_marker/circle_marker.rdata")
# 색상 설정
circle.colors <- c()
#
# 반응형 지도 만들기
m1 <- leaflet() %>%
addTiles(options = providerTileOptions(minZoom = 9, maxZoom = 18)) %>%
# 서울시 경계선
addPolygons(data = bnd,
color = "gold",
fill = NA,
weight = 5) %>%
# 최고가 레스터 데이터
addRasterImage(raster_high,
colors = colorNumeric(palette = c("blue","green","yellow","red"),
domain = values(raster_high),
na.color = "transparent"),
opacity = 0.4) %>%
# 급등 지역 레스터 데이터
addRasterImage(raster_hot,
colors = colorNumeric(palette = c("blue", "green", "yellow", "red"),
domain = values(raster_hot),
na.color = "transparent"),
opacity = 0.4) %>%
# 체크 박스
addLayersControl(baseGroups = c("High Price in 2021", "Hot Price in 2021"),
options = layersControlOptions(collapsed = F)) %>%
# 마커 클러스터링
addCircleMarkers(data = apt_price,
# 경도
lng = unlist(map(apt_price$geometry,1)),
# 위도
lat = unlist(map(apt_price$geometry,2)),
fillColor = circle.colors,
weight = apt_price$py,
clusterOptions = markerClusterOptions(iconCreateFunction=JS(avg.formula)))
#
m1
#
2) 지도 어플리케이션 만들기
# 지도 애플리케이션 만들기
# 반드시 10_1 코드가 실행되어야 함
# 그리드 데이터 sf형을 sp형으로 변환
grid <- as(grid, "Spatial")
# sfg: simple feature geometry
# sfc: simple feature columns (the coordinate)
# sf: simple feature columns + attribute (data.frame)
# 그리드 데이터를 sfc로 변환
grid <- as(grid, "sfc")
grid
# 아파트 가격 데이터와 그리드 데이터 합치기
# 데이터가 있는 그리드만 추출
grid <- grid[which(sapply(st_contains(st_sf(grid), apt_price),length) > 0)]
# 그리드 확인
plot(grid)
# 그리드 추가 함수 라이브러리 준비 = addFeatures
library(leafem)
#
# 반응형 지도 만들기
m2 <- m1 %>%
# 그리드 추가
addFeatures(st_sf(grid), layerId = ~seq_len(length(grid)), color = "gray")
#
3) 그리드 선택할 수 있는 지도 웹 어플리케이션 만들기
# 그리드 선택할 수 있는 지도 웹 어플리케이션 만들기
# 렌더링 함수 없이 실습하여 확인
# 라이브러리
library(sf);library(leaflet);library(tidyverse);library(shiny);library(mapedit);library(DT);library(leafem)
# ui
ui <- fluidPage(
# 그리드 선택 모듈 = 지도에서 선택된 내용이 서버로 전달
selectModUI("selectmap"),
"No response"
)
# server
server <- function(input, output, session){
callModule(selectMod, "selectmap", m2)
}
# shinyApp
shinyApp(ui, server)
#
4) 렌더링 함수 및 결과 출력되는 부분 추가해서 그리드 선택할 수 있는 지도 app 만들기
# 그리드 선택할 수 있는 지도 웹 어플리케이션 만들기
# 렌더링 함수 추가 실습하여 확인
# 라이브러리
library(sf);library(leaflet);library(tidyverse);library(shiny);library(mapedit);library(DT);library(leafem)
# ui
ui <- fluidPage(
# 그리드 선택 모듈 = 지도에서 선택된 내용이 서버로 전달
selectModUI("selectmap"),
# 결과 출력되는 부분 추가
textOutput("sel")
)
# server
server <- function(input, output, session){
df <- callModule(selectMod, "selectmap", m2)
# 렌더링 함수 추가
output$sel <- renderPrint({df()})
}
# shinyApp
shinyApp(ui, server)
#
5) 지도 app 완성하기
* ui 만들기
# 지도 웹 어플리케이션 완성하기
# 상단: 좌 (반응형 지도), 우 (슬라이더-면적, 건축연도)
# 하단: 입력값에 따른 데이터테이블 형태로 데이터 출력
# 반드시 10_1, 10_2 먼저 실행할 것
#
# ui
ui <- fluidPage(
# 상단: 좌 (반응형 지도)
column(width = 9,
selectModUI("selectmap"),
div(style = "height:40px;")),
# 상단: 우 (슬라이더-면적, 건축연도)
column(width = 3,
sliderInput(inputId = "range_area", # ID
"Area", # 제목
min = 0, max = 350, # 범위: 최소값, 최대값
value = c(0, 200)), # default 값
sliderInput(inputId = "range_con", # ID
"Construction year", # 제목
min = 1960, max = 2021, # 범위: 최소값, 최대값
value = c(2000, 2021))), # default 값
# 하단: 입력값에 따른 데이터테이블 형태로 데이터 출력
column(width = 12,
dataTableOutput(outputId = "table"),
div(style = "height:200px;"))
)
* 서버 만들기 - 슬라이드 범위 선택 필터링
# server
server <- function(input, output, session){
# 반응식
# A: 면적과 건축연도 범위에 해당하는 데이터 추출
all <- reactive({
all <- subset(apt_price, area >= input$range_area[1] & area <= input$range_area[2] & con_year >= input$range_con[1] & con_year <= input$range_con[2])
return(all)})
* 지도 데이터 불러오기
# B: 선택된 그리드 저장
# m2에 지도 정보가 담겨 있음.
sel <- callModule(selectMod, "selectmap", m2)
# A 와 B 교집합
* 초기 반응 결과 필터링
# 초기 반응값 저장
rv <- reactiveValues(intersect = NULL, selectgrid = NULL)
# 반응 결과 저장
observe({
# grid selected => 선택된 그리드 저장
gs <- sel()
# 선택(selected == TRUE)된 그리드 ID를 숫자형으로 변환하여 그리드 데이터에서 가져오기(sf형으로 변환)
rv$selectgrid <- st_sf(grid[as.numeric(gs[which(gs$selected == TRUE),"id"])])
# 데이터가 있는 경우
if(length(rv$selectgrid) > 0){
# A & B 교집합
rv$intersect <- st_intersects(rv$selectgrid, all())
# geometry 삭제
# rv$intersect 결과는 리스트
rv$sel <- st_drop_geometry(apt_price[unlist(rv$intersect), ])
} else{ # 데이터가 없는 경우
rv$intersect <- NULL
}
})
* 데이터 테이블 저장 후 실행까지
# rv$sel => 데이터테이블로 저장(렌더링 함수 사용)
output$table <- DT::renderDataTable({
dplyr::select(rv$sel,
# 열 선택
ymd, addr_1, apt_nm, price, area, floor, py) %>%
arrange(desc(py))},
extensions = 'Buttons',
options = list(dom = 'Bfrtrip',
scrollY = 300,
scrollCollapse = T,
paging = T,
buttons = c('excel'))
)
}
# shinyApp
shinyApp(ui, server)
#
지도 앱 완성
6) 지도앱 배포판 전용 코드
# 배포판 작성
# 10_1, 10_2, 10_3, 10_4, 10_5 종합적으로 작성
# 1. 라이브러리 준비
library(sp);library(sf);library(leaflet);library(tidyverse);library(raster);library(rgdal);library(tmap);library(mapedit);library(leafem);library(ggfortify);library(grid);library(shiny);library(DT)
# 2. 데이터 불러오기
# 아파트 가격
load("./data/apt_price.rdata")
# 서울시 그리드 데이터
grid <- st_read("./data/sigun_grid/seoul.shp")
# 서울시 경계선 데이터
bnd <- st_read("./data/sigun_bnd/seoul.shp")
# 최고가 레스터 데이터
load("./data/raster_high.rdata")
# 급등 지역 레스터 데이터
load("./data/raster_hot.rdata")
# 3. 그리드 데이터 전처리
# 그리드 데이터 sf형을 sp형으로 변환
grid <- as(grid, "Spatial")
# sfg: simple feature geometry
# sfc: simple feature columns (the coordinate)
# sf: simple feature columns + attribute (data.frame)
# 그리드 데이터를 sfc로 변환
grid <- as(grid, "sfc")
# 아파트 가격 데이터와 그리드 데이터 합치기
# 데이터가 있는 그리드만 추출
grid <- grid[which(sapply(st_contains(st_sf(grid), apt_price),length) > 0)]
# 4. 마커 클러스터
# 마커 클러스터링 옵션 설정
# 상위 10%, 하위 10%, 나머지
# q10 <- quantile(apt_price$py, probs = seq(.1, .9, by = .1))
# 상위 10% = 90%
pct_90 <- as.numeric(quantile(apt_price$py, probs = seq(.1, .9, by = .1))[9])
# 하위 10% = 10%
pct_10 <- as.numeric(quantile(apt_price$py, probs = seq(.1, .9, by = .1))[1])
# 마커 클러스터링 함수 불러오기
load("./data/circle_marker/circle_marker.rdata")
# 색상 설정
circle.colors <- c()
# 5. 반응형 지도 만들기 => shiny application 내부
# 6. shiny application
# ui
ui <- fluidPage(
# 상단: 좌 (반응형 지도)
column(width = 9,
selectModUI("selectmap"),
div(style = "height:40px;")),
# 상단: 우 (슬라이더-면적, 건축연도)
column(width = 3,
sliderInput(inputId = "range_area", # ID
"Area", # 제목
min = 0, max = 350, # 범위: 최소값, 최대값
value = c(0, 200)), # default 값
sliderInput(inputId = "range_con", # ID
"Construction year", # 제목
min = 1960, max = 2021, # 범위: 최소값, 최대값
value = c(2000, 2021))), # default 값
# 하단: 입력값에 따른 데이터테이블 형태로 데이터 출력
column(width = 12,
dataTableOutput(outputId = "table"),
div(style = "height:200px;"))
)
# server
server <- function(input, output, session){
# 반응식
# A: 면적과 건축연도 범위에 해당하는 데이터 추출
all <- reactive({
all <- subset(apt_price, area >= input$range_area[1] & area <= input$range_area[2] & con_year >= input$range_con[1] & con_year <= input$range_con[2])
return(all)})
# B: 선택된 그리드 저장
sel <- callModule(selectMod, "selectmap",
leaflet() %>%
addTiles(options = providerTileOptions(minZoom = 9, maxZoom = 18)) %>%
# 서울시 경계선
addPolygons(data = bnd,
color = "gold",
fill = NA,
weight = 5) %>%
# 최고가 레스터 데이터
addRasterImage(raster_high,
colors = colorNumeric(palette = c("blue","green","yellow","red"),
domain = values(raster_high),
na.color = "transparent"),
opacity = 0.4) %>%
# 급등 지역 레스터 데이터
addRasterImage(raster_hot,
colors = colorNumeric(palette = c("blue", "green", "yellow", "red"),
domain = values(raster_hot),
na.color = "transparent"),
opacity = 0.4) %>%
# 체크 박스
addLayersControl(baseGroups = c("High Price in 2021", "Hot Price in 2021"),
options = layersControlOptions(collapsed = F)) %>%
# 마커 클러스터링
addCircleMarkers(data = apt_price,
# 경도
lng = unlist(map(apt_price$geometry,1)),
# 위도
lat = unlist(map(apt_price$geometry,2)),
fillColor = circle.colors,
weight = apt_price$py,
clusterOptions = markerClusterOptions(iconCreateFunction=JS(avg.formula))) %>%
# 그리드 추가
addFeatures(st_sf(grid), layerId = ~seq_len(length(grid)), color = "gray")
)
# A 와 B 교집합
# 초기 반응값 저장
rv <- reactiveValues(intersect = NULL, selectgrid = NULL)
# 반응 결과 저장
observe({
# grid selected => 선택된 그리드 저장
gs <- sel()
# 선택(selected == TRUE)된 그리드 ID를 숫자형으로 변환하여 그리드 데이터에서 가져오기(sf형으로 변환)
rv$selectgrid <- st_sf(grid[as.numeric(gs[which(gs$selected == TRUE),"id"])])
# 데이터가 있는 경우
if(length(rv$selectgrid) > 0){
# A & B 교집합
rv$intersect <- st_intersects(rv$selectgrid, all())
# geometry 삭제
# rv$intersect 결과는 리스트
rv$sel <- st_drop_geometry(apt_price[unlist(rv$intersect), ])
} else{ # 데이터가 없는 경우
rv$intersect <- NULL
}
})
# rv$sel => 데이터테이블로 저장(렌더링 함수 사용)
output$table <- DT::renderDataTable({
dplyr::select(rv$sel,
# 열 선택
ymd, addr_1, apt_nm, price, area, floor, py) %>%
arrange(desc(py))},
extensions = 'Buttons',
options = list(dom = 'Bfrtrip',
scrollY = 300,
scrollCollapse = T,
paging = T,
buttons = c('excel'))
)
}
# shinyApp
shinyApp(ui, server)
#
일반적으로 해당 파일 및 data 파일 폴더만 클릭함.
하지만 상황에 따라 전체 클릭으로 확인하기도.. <-- 이 부분은 좀 더 자세히 확인하는걸로
* 핵심
- 렌더링 함수 : renderText
- 반응식을 왜 쓰는지 : 값을 입력했을 때 해당 되는 데이터를 출력하기 위해
- 마커 클러스터링을 왜 쓰는지 : 데이터 왜곡을 방지하기 위함
- 필터링 작업을 해야 하는 이유 : 데이터 오류 방지를 위해
- 배포하는 방법 : shiny Publishing
'배운 책들 정리 > 공공데이터로 배우는 R 데이터 분석 with 샤이니' 카테고리의 다른 글
공공데이터 with 샤이니 12_2 - 샤이니 app 활용 사례 (커피 전문점 접근성) (0) | 2023.03.15 |
---|---|
공공데이터 with 샤이니 12 - 샤이니 app 활용 사례 (지진 발생 분석) (1) | 2023.03.15 |
공공데이터 with 샤이니 7,8 - 분석 주제를 지도로 시각화하기, 통계 분석과 시각화 (0) | 2023.03.09 |
공공데이터 with 샤이니 6,7 - 지오 데이터 프레임, 분석 주제를 지도로 시각화하기 (0) | 2023.03.08 |
공공데이터 with 샤이니 4~5 - 데이터 전처리, 지오 코딩 (0) | 2023.03.07 |