R4CR

Day3 - shiny | 2024-09-02
Jinhwan Kim

Overview

Shiny

Easily build rich and productive interactive web apps in R.

Interactive: 사용자의 요청에 따라 결과가 다름.

ex) 내가 입력한 데이터로 계산한 결과를 보여줘

Web apps: 웹에서 (without R) 실행 되는 프로그램

ex) 샘플수 계산기

Shiny의 목적

  • 상황: 사용자가 R로 분석을 하고 싶음
  • 그러나 사용자는 R을 개발하고 싶진 않음

Shiny의 목적

  • R을 웹 브라우저(크롬)에서도 사용할 수 있게 개발
  • 이제 가능, 그러나 복잡한 계산은 어려움
  • Quarto

Shiny의 목적

  • 사용자의 입력을 토대로 별도의 서버에서 계산하고, 그 결과를 다시 보여줄 수 있게 개발
  • Shiny
  • 각각 UI, Server

First Shiny

Shiny 실습 (with posit cloud)

  1. New Project
  2. New Project from Template
  3. Shiny App Publishing with Rstudio

Shiny 실습 2

Shiny App은 app.R이라는 파일에 코드를 작성하고, 오른쪽 위 버튼으로 실행한다.

주의 버튼의 오른쪽 작은 삼각형 버튼을 눌러 으로 변경: Shiny를 새로운 창이 아닌 아닌 R 스튜디오의 뷰어 패널 실행

Shiny 실습 3

Shiny 실행 후 지도의 지점을 클릭하면 아래에 해당 지점의 데이터를 보여준다.

Shiny의 종료

Shiny의 실행은 이미 runApp(), shinyApp() 이라는 함수를 실행하기 때문에 R 콘솔에서 다른 명령어를 실행할 수 없다. Shiny를 종료하기 위해서는 뷰어에서 을 누르거나, 콘솔에서 을 클릭 혹은 키로 종료한다

조금 더 쉬운 Shiny

Try this

# pak::pkg_install('shiny')
library(shiny)
runExample("01_hello")
  • 실행결과:

First Shiny

  • Number of bins를 바꾸면 결과도 실시간으로 바뀌는 것을 확인할 수 있다.
  • Reactive Programming: 사용자의 입력에 따라 반응하여 결과를 생성

Shiny App의 구조

  • 01_hello의 코드 (app.R)
library(shiny)

ui <- fluidPage(
  titlePanel("Hello Shiny!"),
  sidebarLayout(
    sidebarPanel(
      sliderInput(...)
    ),
    mainPanel(
      plotOutput(outputId = "distPlot")
    )
  )
)

server <- function(input, output) {
  output$distPlot <- renderPlot({...})
}

shinyApp(ui = ui, server = server)

Shiny app은 UIServer 로 구성

  • UI(L3~L13): 앱이 어떻게 보일지
  • Server(L15~L17): 앱이 어떻게 작동할 지

Shiny App의 해석 - UI

  • 01_hello의 코드 (app.R)
ui <- fluidPage(
  titlePanel("Hello Shiny!"),
  sidebarLayout(
    sidebarPanel(
      sliderInput(
        inputId = "bins",
        label = "Number of bins:",
        min = 1,
        max = 50,
        value = 30
      )
    ),
    mainPanel(
      plotOutput(outputId = "distPlot")
    )
  )
)

Shiny App의 해석 - Server

  • 01_hello의 코드 (app.R)
server <- function(input, output) {
  output$distPlot <- renderPlot({
    x <- faithful$waiting
    bins <- seq(
      min(x), max(x), 
      length.out = input$bins + 1
    )
    hist(x,
      breaks = bins, 
      col = "#75AADB", border = "white",
      xlab = "Waiting time to next eruption (in mins)",
      main = "Histogram of waiting times"
    )
  })
}
  1. faithful 데이터에서 input$bins + 1개 만큼 bins를 생성
  2. histogram으로 시각화
  3. 한 결과를 output$distPlotrenderPlot으로 전달
  • input: 사용자의 입력값 (sliderInput)
  • output: 사용자에게 보여줄 값 (plotOutput)

Shiny 핵심 로직

“UI에서 **Input으로 입력을 받고 server의 계산을 거쳐 output의 **Outputrender**를 사용하여 보여준다.”

Shiny 핵심 로직

이전 예시는 sliderInput으로 입력을 받고, output의 plotOutputrenderPlot을 사용하여 보여준다.

Shiny 만들기

전체 흐름

실습 목표

  • 데이터를 읽고,
  • 특정 조건에 해당하는 데이터만 선택
  • 계산에 활용하여
  • 시각화를 보여주는 Shiny app 만들기

사전준비

작업순서

  1. R에서 기능 만들기
  2. UI & Server 만들기
  3. 실행하기 (배포하기)

Shiny App 만들기 (Local Rstudio)

  1. File -> New File -> Shiny Web app
  2. Single file (app.R)

New file로 하는 경우

  1. Run App버튼이 생기고
  2. 나중에 shinyapps.io에 배포가 쉬워짐

Shiny snippet

Rstudio에서는 Shiny app을 만들기 위한 snippet(템플릿)을 제공.

사용방법:

  1. 소스(Source) 혹은 콘솔(Console)에 Shiny를 입력 후
  2. 나타나는 shinyapp에서 탭을 눌러 선택
  3. 자동 완성

간단한 구조의 앱을 빠르게 만들 수 있음

R에서 기능 만들기

  • 데이터 준비
  • 데이터 선택
  • 시각화
library(dplyr)
library(ggplot2)
v <- read.csv(...)

v %>% 
  filter(...) %>%
  summarise(m = mean(), by = ...) %>%
  ggplot(...)

를 차례차례 구현

fileURL <- 
"https://github.com/zarathucorp/R4CR-content/raw/main/example_g1e.csv"
v <- read.csv(fileURL)

summary(v$EXMD_BZ_YYYY)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
   2009    2010    2012    2012    2014    2015 

R에서 기능 만들기

  • 데이터 준비
  • 데이터 선택
  • 시각화

연도(EXMD_BY_YYYY)를 사용자로부터 입력 받아서 해당 데이터만 활용하기 위한 목적

selectYear = 2010
v2 <- v %>% 
  filter(EXMD_BZ_YYYY == selectYear)

summary(v2$HGHT)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  139.0   159.0   165.0   164.9   171.2   186.0 

R에서 기능 만들기

  • 데이터 준비
  • 데이터 선택
  • 시각화

해당 데이터의 키의 평균 계산

v2 %>% 
  ggplot(aes(x = HGHT, y = WGHT)) +
  geom_point()

UI 만들기

이런 형태를 만들어 보자

UI 만들기

필요한 것

  1. File (v)- Input
  2. Select (selectYear)- Input
  3. Plot (ggplot)- Output


  • fileInput
  • selectInput

UI 만들기 2

필요한 것

  1. File (v)- Input
  2. Select (selectYear)- Input
  3. Plot (ggplot)- Output


  • renderPlot
  • plotOutput

UI 만들기 3

ui <- fluidPage(
  fileInput(
    inputId = 'file', # 입력값 구분
    label = 'upload' # 어떻게 보일지
  ),
  selectInput(
    inputId = 'year', 
    label = 'select Year',
    choices = 2009:2015
  )
)

server<- function(input, output, session){
  
}

shinyApp(ui = ui, server = server)

아직 아무 작동 안함

Server 만들기

  • ?fileInput
ui <- fluidPage(
  ...
)

server<- function(input, output, session){
  observeEvent(input$file, {
    fileObj <- input$file
    v <- read.csv(fileObj$datapath)
    print(dim(v))
  })
}

shinyApp(ui = ui, server = server)

데이터를 업로드 하면 v에 저장하고, dimension을 출력

Server 만들기 2

  • ?selectInput
server<- function(input, output, session){
  v <- ''
  
  observeEvent(input$file, {
    ...
    v <<- read.csv(fileObj$datapath)
  })
  
  observeEvent(input$year, {
    req(v)
    print(input$year)
    v2 <- v %>% 
      filter(EXMD_BZ_YYYY == input$year)
    print(head(v2))
  })
  
}

shinyApp(ui = ui, server = server)
  • vinput$file 에서만 사용되기 때문에 전체에서 사용 될 수 있게 수정
  • Reactive를 사용해도 되는데 나중에 다룸.

Server 만들기 3

  • ?plotOutput
ui <- fluidPage(
  ...
  plotOutput(outputId = 'plot')
)

server<- function(input, output, session){
  ...
  v <- ''
  
  observeEvent(input$year, {
    req(v)
    
    v2 <- v %>% 
      filter(EXMD_BZ_YYYY == input$year)
    
    output$plot <- renderPlot({
      v2 %>%
        ggplot(aes(x = HGHT, y = WGHT)) +
        geom_point()
    })
    
  })
  
}

shinyApp(ui = ui, server = server)
  • Year 선택할때마다 plot 결과값 바뀌는 것 확인

중간정리

  • Shiny App은 Input을 받고, Output을 보여주는 UI
  • Input으로 부터 결과를 계산하는 Server로 구성
  • Input 은 ExInput(), Output 은 ExOutput() + renderEx()로 사용
  • 다양한 블록이 있으므로 필요에 따라 활용할 수 있음

Layout

  • UI를 조금 더 깔끔하게 배치
  • 다양한 레이아웃, 패키지가 있지만 아래 2개를 다룰 예정

sidebarLayout

  • ?sidebarLayout
sidebarLayout(
  sidebarPanel,
  mainPanel,
  position = c("left", "right"),
  fluid = TRUE
)

sidebarPanel(..., width = 4)

mainPanel(..., width = 8)
  • sidebarPanel에는 사용자가 입력하는 UI
  • mainPanel에는 계산 결과를 보여주는 UI
  • width: 12가 100%

sidebarLayout

  • 이전에 만든 App의 UI를 sidebarLayout으로 변경
ui <- fluidPage(
  sidebarLayout(
    sidebarPanel(
      h3("Sidebar Panel"),
      fileInput(
        inputId = 'file', 
        label = 'upload'
      ),
      selectInput(
        inputId = 'year', 
        label = 'select Year',
        choices = 2009:2015
      )
    ),
    mainPanel(
      h3("Main Panel"),
      plotOutput(
        outputId = 'plot'
      )
    )
  )
)

Shiny 배포 (온라인 공유)

Shinyapps.io

https://www.shinyapps.io/

Shiny를 공유하기 위한 클라우드 서비스.

  1. 계정 만들기
  2. 파일을 app.R이라고 저장
  3. Publish Application
  4. 진행 (콘솔의 Deploy)

Shinyapps.io

Add New Account에서 ShinyApps.io 선택

Shinyapps.io

  • Shinyapps.io 계정에서 Tokens 선택
  • 이후 Add Token, Show 선택

Shinyapps.io

  • Show Secret, Copy to clipboard 선택
  • 토큰 값을 이전 창에 그대로 붙여넣기

Shinyapps.io

이후 shinyapps.io에 배포 가능

정리

  • Shiny App은 Input을 받고, Output을 보여주는 UI

  • Input으로 부터 결과를 계산하는 Server로 구성

  • Input 은 ExInput(), Output 은 ExOutput() + renderEx()로 사용

  • 다양한 블록이 있으므로 필요에 따라 활용할 수 있음

  • 레이아웃을 통해 앱의 UI / UX을 개선하거나

  • reactive를 통해 데이터 처리 흐름을 조절할 수 있으며.

  • shinyapps.io 를 통해 모두가 사용할 수 있게 공유도 가능