[R Shiny] Basic

Author

SEOYEON CHOI

Published

March 9, 2026

Project

[Project Title] R Shiny 기반 Real-Time Data Dashboard 구축

[Project Overview] - R Shiny 기반 실시간 임상 데이터 시각화 및 모니터링 대시보드 개발 - 임상 데이터 모니터링 프로세스 효율화 및 의사결정 지원, 리포팅 시간 단축

[My role] - API 기반 데이터 수집 후 전처리 및 시각화 파이프라인 구축 - R Shiny를 활용한 임상 데이터 모니터링 대시보드 개발 - 임상 데이터 요약 및 시각화를 위한 통계 분석 및 데이터 처리 - 주요 임상 지표(환자 등록 현황, AE 발생 등) 실시간 모니터링 기능 구현 - 연구팀 의사결정을 지원하기 위한 데이터 시각화 및 인터랙티브 리포팅 구현

[Analysis Workflow Diagram] - 데이터 수집(API) → 데이터 전처리 → 시각화 → 실시간 모니터링 대쉬보드 구현

[Tools] R (Shiny)

  • Book

Mastering Shiny

Example

link

Basic concept

app.R

library(shiny)

shinyApp(ui = ui, server = server)

ui.R

library(shiny)
library(bslib)

# Define UI for app that draws a histogram ----
ui <- page_sidebar(
  # App title ----
  title = "Hello Shiny!",
  # Sidebar panel for inputs ----
  sidebar = sidebar(
    # Input: Slider for the number of bins ----
    sliderInput(
      inputId = "bins",
      label = "Number of bins:",
      min = 1,
      max = 50,
      value = 30
    )
  ),
  # Output: Histogram ----
  plotOutput(outputId = "distPlot")
)

server.R

# Define server logic required to draw a histogram ----
server <- function(input, output) {

  # Histogram of the Old Faithful Geyser Data ----
  # with requested number of bins
  # This expression that generates a histogram is wrapped in a call
  # to renderPlot to indicate that:
  #
  # 1. It is "reactive" and therefore should be automatically
  #    re-executed when inputs (input$bins) change
  # 2. Its output type is a plot
  output$distPlot <- renderPlot({

    x    <- faithful$waiting
    bins <- seq(min(x), max(x), length.out = input$bins + 1)

    hist(x, breaks = bins, col = "#007bc2", border = "white",
         xlab = "Waiting time to next eruption (in mins)",
         main = "Histogram of waiting times")

    })

}

Process

  • Kor
    • R Shiny 앱은 UI와 Server 두 부분으로 구성됩니다.
    • 먼저 UI에서 화면의 입력과 출력 요소를 정의하고,
    • Server에서는 입력값을 받아 처리하고 출력값을 생성합니다.
    • 마지막으로 shinyApp(ui, server)를 통해 앱을 실행합니다.
  • Eng
    • A Shiny app has two main parts: the UI and the Server.
    • The UI defines the inputs and outputs that the user sees,
    • and the Server processes the inputs and generates the outputs.
    • Finally, we connect them with shinyApp(ui, server) to run the application.
    • For example, I can put a slider in the UI and then display the selected value as text through the Server.”

ui,server두 파일만 생성하고 r 콘솔에 runapp('name')이렇게 작성해서 실행하는 방법과 appui,server 내용 다 작성해서 파일 하나로 실행하는 방법과 ui,server,app 세 파일 다 만들어서 app에서 실행하는 방법이 있다.

keywords

  • UI → layout, inputs/outputs
  • Server → logic, processing, rendering
  • shinyApp() → connect & run
  • Process → Design UI → Implement Server → Execute

file structure

1) 단일 파일 방식 (app.R만 있음)

  • app.R 안에 ui, server 코드를 전부 작성
  • 마지막에 shinyApp(ui, server) 호출
library(shiny)

ui <- fluidPage(
  titlePanel("Hello Shiny"),
  textOutput("txt")
)

server <- function(input, output, session) {
  output$txt <- renderText("Hi, this is Shiny!")
}

shinyApp(ui, server)

2) 분리 방식 (ui.R + server.R)

  • 같은 폴더 안에 두면 Shiny가 자동으로 둘을 읽어서 실행

→ 실행: runApp(“myapp”)

R console에 실행

ui.R: 화면 정의

# ui.R
ui <- fluidPage(
  titlePanel("Hello Shiny"),
  textOutput("txt")
)

server.R: 로직 정의

# server.R
server <- function(input, output, session) {
  output$txt <- renderText("Hi, this is Shiny!")
}

3) 세 개 다 있는 경우 (app.R + ui.R + server.R)

  • Shiny는 app.R이 있으면 무조건 app.R을 실행
  • 따라서 이 경우 ui.R/server.R은 자동으로 쓰이지 않음.
  • 다만 app.R 안에서 source(“ui.R”), source(“server.R”)로 불러와서 실행할 수 있음.

Shiny App Account

  • Local Run → no account needed, runApp(), Run App button

  • Visibility → runs only on your computer

  • Online Sharing → account required

  • Hosting Options → shinyapps.io, RStudio Connect, Shiny Server

  • Deployment → rsconnect::setAccountInfo(), deployApp()

  • Process → Develop locally → Connect account → Deploy to server

  • 내 컴퓨터에서 실행 (계정 불필요)

    • app.R만 있으면 RStudio에서 바로 Run App 버튼이나 runApp()으로 실행 가능.
    • 이 경우 앱은 내 컴퓨터에서만 보임 (즉, 본인 PC에서만 확인 가능).
    • 계정 연결 필요 없음.
  • 온라인 배포 (계정 필요)

    • 다른 사람이 인터넷으로 접속하게 하려면 계정이 필요. 대표적으로: shinyapps.io(RStudio에서 제공, 무료/유료 플랜 있음)
      • rsconnect::setAccountInfo()로 계정 연결 필요
      • rsconnect::deployApp()으로 앱 업로드
    • RStudio Connect (회사/기관용 서버)
    • 자체 Shiny Server (리눅스 서버에 직접 설치)

difference between reactive vs observe

  • Kor
    • Reactive는 값을 반환하는 함수이고, Observe는 단순히 동작을 실행합니다.
    • Reactive는 입력값을 받아 새로운 출력값을 만들 때 쓰이고, 그 결과를 다른 표현식이나 출력에서 다시 활용할 수 있습니다.
    • 반면, Observe는 값 자체를 반환하지 않고, 예를 들어 로그 출력이나 알림 같은 부수 효과(side effect)를 처리할 때 주로 사용됩니다.
  • Eng
    • Reactive returns a value, while Observe does not.
    • Reactive expressions are used to create values that can be reused by other parts of the app, for example, calculations or transformations based on user input.
    • On the other hand, Observe is mainly used for side effects, such as printing logs, sending a notification, or updating something without returning a value.
  • Kewords
    • Reactive → returns value, reusable, dependency tracking, computations
    • Observe → no return value, side effects, triggers, monitoring
    • Key difference → Reactive = “create value” / Observe = “perform action”

The code that I use to show R shiny results

  • Kor
    • Shiny에서 결과를 보여주려면, 먼저 UI에 출력 자리(output placeholder)를 만듭니다. 예를 들어 plotOutput, tableOutput, textOutput 같은 함수를 씁니다.
    • 그리고 Server에서는 대응되는 render 함수(renderPlot, renderTable, renderText)를 사용해서 실제 출력을 생성합니다.
  • Eng
    • In Shiny, to display results on the UI, I first create an output placeholder in the UI using functions like plotOutput, tableOutput, or textOutput.
    • Then, in the Server, I use the corresponding render functions such as renderPlot, renderTable, or renderText to generate and connect the actual output.
  • Keyeords
    • UI → output placeholder (plotOutput, tableOutput, textOutput)
    • Server → render functions (renderPlot, renderTable, renderText)
    • Process → Placeholder in UI → Render in Server → Display in App

반응이 너무 느리다면? 생성이 너무 느리다면?

  1. log로 병목 현상이 생긴 구간 찾기
shiny::reactlog_enable(); 
  1. 반응 최소화
  • 중복 계산 없애기
  • 매 입력마다 계산되는 것이 아닌 이벤트로 트리거되도록
  • 가장 큰 원인은 매번 데이터를 불러오면 발생할 것. global에 옮겨서 데이터는 한 번만 불러오도록