공지

이번에 준비한 튜토리얼은 제 강의를 듣는 과거-현재-미래 수강생분들을 위해 준비한 자료이다. 많은 도움이 되기를 바란다

이번에 준비한 Tutorial 코로나 세계현황을 Shiny Dashboard로 만들어 가는 과정을 담았다.

I. Shiny 소개

지난시간에 Shiny에 관한 대략적인 소개를 했다. 처음 이 페이지를 방문한 사람들 위해 shiny tutorial 01 - get started 에서 짧게 확인하기를 바란다.

II. Shiny App Structure

아래 샘플 코드를 확인하자.

# load the shiny package
library(shiny)

# 화면 구성 (UI) - 프론트엔드
ui <- fluidPage(
  numericInput(inputId = "n", label = "Sample size", value = 25),
  plotOutput(outputId = "hist")
)

# 서버 구성 - 벡엔드
server <- function(input, output) {
  output$hist <- renderPlot({
    hist(rnorm(input$n))
 
    # 결과물을 만들어내는 코드 작성
    
  })
}

# shiny app 호출
# 프로젝트 진행 시, 폴더 안에
# 파일명은 app.R 형태로 저장한다. 
shinyApp(ui = ui, server = server)
## 
## Listening on http://127.0.0.1:7908

Shiny의 기본 구조는 UI, Server, shinyApp 형태로 구성이 된다. - UI: 사용자 인터페이스, 즉 화면단을 만드는 작업을 진행한다. - Server: 사용자 인터페이스가 제대로 기능할 수 있도록 지원하며, Server단에서, 데이터 전처리, 수집, 시각화 작업이 이루어진다. 즉, 이 때에는 R의 문법이 사용되는 것이다. - shinyApp: UIServer객체별로 저장이 되면, shinyApp을 통해 호출하면서 실행이 된다.

각각의 App이 복잡하면 복잡해질 수록 UI, Server, shinyApp의 파일로 재구현되어 관리가 될 수 있으며, Modularizing의 개념도 함께 들어간다. 즉, 이 때부터는 웹개발 로직의 형태와 비슷하게 전개되는데, 이제 프로그래밍에 입문하는 사람들을 위해서는 추천하지 않는다. Shiny를 추천하는 이유는 빠른 프로토타입이 가능해서이기 때문에, 가급적 이 원칙을 지켰으면 좋겠다. 냉정하게 말하면 복잡해질 것 같으면, 여기서부터는 고민해야 한다. BI Tool을 쓸것인가? 아니면 프론트개발자와 협업을 할 것인가?

만약, 조금 더 복잡한 ShinyApp을 개발하고 싶다면, 아래 글에서 추가적인 개념을 익혔으면 한다.

다시 추가로 말하자면, 여기서부터는 데이터분석가(Data Analyst)의 역량보다는 프론트엔드 개발자(Front-End Developer)의 역량의 성격이 훨씬 더 짙어진다. 이 부분은 꼭 참고하기를 바란다.

(1) ui 또는 ui.R

사용자에게 보여주는 화면을 만들어주는 역할을 하며, 보통 Input & Output function으로 통용된다. 대표적인 함수는 아래와 같다.

대표적인 Input 관련 함수는 아래와 같다. - textInput(): 사용자가 텍스트를 입력할 수 있다. - dateRangeInput(): 사용자가 날짜 등을 입력할 수 있다. - fileInput(): 사용자가 csv파일 등을 입력할 수 있다.

대표적인 Output 관련 함수는 아래와 같다. - textOutput() : 입력한 텍스트가 출력된다. - tableOutput(): 데이터프레임 등이 출력된다. - imageOutput(): 이미지 등이 출력된다.

조금 더 자세한 내용이 함수가 궁금하다면, 강사의 강의안을 참조하거나 또는 Shiny Cheet Sheet에서 확인하기를 바란다. 마지막으로 전체 함수가 궁금한 수강생들은 Function Reference를 참고하기를 바란다.

이 때 중요한 것은 각 함수 안에서 inputId=your_inputId 또는 outputId=your_outputId가 중요하다. 각각의 ID명을 매개로 Server단과 연결이 되기 때문이다. 초반에 많은 에러들은 사실 여기에서 발생이 된다.

아래 샘플 코드를 보자.

ui <- fluidPage(
  Input(inputId = myinput, label = mylabel, ...)
  Output(outputId = myoutput, ...)
)

server <- function(input, output){
  output$myoutput <- render*({
    # code to build the output.
    # If it uses an input value (input$myinput),
    # the output will be rebuilt whenever
    # the input value changes
  })}

ui.R에 있는 outputID명과, inputID명이 server.R의 그것과 동일해야 한다.

(2) server 또는 server.R

ui에서 파라미터(ex: outputId) 형태로 값이 넘어오면 파라미터를 받아서 처리하고 결과를 보여준다. UI에 있는 output()함수들의 각각의 구성요소는 server에서 render*() 함수와 연결이 된다. 예를 들면 아래와 같다.

output$hist <- renderPlot({ 
    hist(rnorm(input$myinput)) 
  })
  • renderPlot(): 그래프 작성 결과를 출력하는 함수다.
  • renderText(): 텍스트 작성 결과를 출력하는 함수다.
  • renderTable(): 테이블 작성 결과를 출력하는 함수다.

간단하게 ui와 server 관계를 정리하면 아래와 같다.

ui() 에서는 plotOutput(outputId = "myoutput"), server()에서는 output$myoutput <- renderPlot({...}) 정리될 수 있고, 이 때 두 객체를 연결하는 인자는 ouputIdmyouput이다.

Samples

매우 간단한 소스코드를 입력하면서 uiserver가 서로 어떻게 연동이 되는지 확인한다. 다만 이 때에는 numericInputlabel을 영어가 아닌 한글로 샘플수라 명명했다.

# 패키지 로드
library(shiny)

# ui 디자인
ui <- fluidPage(
  numericInput(inputId = "myNumber", label = "샘플수", value = 25),
  plotOutput(outputId = "myHist")
)

# 서버 개발
# myHist와 myNumber를 꼭 확인한다. 
server <- function(input, output) {
  output$myHist <- renderPlot({
    hist(rnorm(input$myNumber))
  })
}

# shinyApp에서 ui와 server를 호출한다. 
shinyApp(ui = ui, server = server)
## 
## Listening on http://127.0.0.1:6753

Congratulation! You Mastered Shiny Structure.