shinylive 를 활용한 quarto 블로그에 shiny 추가 방법

webR의 개선 버전인 shinylive 패키지를 사용하여 정적 페이지에 shiny application 추가하기

R
shiny
githubpage
documentation
website
quarto
Author
Published

March 5, 2024

Review wasm

이전에 작성한 에서 별도의 서버 없이 작동하는 정적 페이지에서 어떻게 shiny application을 사용할 수 있는 방법을 소개한 적 있다.

이 방법의 핵심은 wasm이라는 기술로, 웹 브라우저에서 사용할 수 있게 변환 된 R과 Shiny 관련 라이브러리, 파일들을 불러오고 이를 활용하는 방법이었는데, wasm의 가장 큰 문제는 R 개발자들에게도 환경 설정 자체가 어렵다는 것이었다.

다행히 몇개월 정도의 시간이 지나고 이 환경 설정을 해결해주는 R 패키지가 나왔고, 이를 활용하여 정적 페이지에 shiny application을 추가하는 방법을 소개하고자 한다.

shinylive

shinylive는 python 버전r 버전이 있으며, 이 글에서는 r 버전을 기준으로 소개한다.

shinylive는 웹 페이지 생성에 필요한 HTML, Javscript, CSS 등의 요소와 shiny 를 사용하기 위한 wasm 관련 파일들을 생성하는 일을 한다.

shinylive로 만든 예시는 이 링크에서 확인할 수 있다.

shinylive 설치

shinylive는 CRAN에 올라가 있기도 하지만 최근 릴리즈 된 버전이 0.1.1인만큼 수시로 업데이트 될 수 있어 github의 최신 버전을 사용하는 것을 권장한다. 추가로 pak는 최근 posit에서 R 패키지를 설치하기 위해 권장하는 R 패키지로, 기존의 install.packages(), remotes::install_github() 등의 함수를 대체할 수 있다.

# install.packages("pak")
pak::pak("posit-dev/r-shinylive")
Version

통상적으로 1.0 이전의 버전은 아직 개발 중인 버전이라고 생각해도 좋다.

shinylive 사용방법

shinylive는 기존에 만든 shiny application에 wasm을 추가하는 것으로 생각할 수 있다. 즉, 먼저 shiny application을 만들어야 한다.

예시 실습을 위해 shiny에서 기본으로 제공하는 코드를 사용한다.(이는 Rstudio 콘솔에서 shiny::runExample("01_hello")를 입력해서 확인할 수도 있다.)

library(shiny)

ui <- fluidPage(
  titlePanel("Hello Shiny!"),
  sidebarLayout(
    sidebarPanel(
      sliderInput(
        inputId = "bins",
        label = "Number of bins:",
        min = 1,
        max = 50,
        value = 30
      )
    ),
    mainPanel(
      plotOutput(outputId = "distPlot")
    )
  )
)

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"
    )
  })
}

shinyApp(ui = ui, server = server)

이 코드는 아래 그림과 같이 사용자의 입력에 반응하여 갯수만큼 histogram을 만드는 간단한 shiny application을 만들어 낸다.

이 코드를 shinylive를 사용해 정적인 페이지를 만드는 방법은 2가지가 있는데 하나는 별도의 웹페이지로 만들어내는 것이고, 다른 하나는 이 기술 블로그 같은 quarto 블로그 페이지에 내부 콘텐츠로 심는 것이다.

먼저 별도의 웹페이지를 만드는 방법은 다음과 같다.

shinylive via Web page

별도의 정적 웹페이지에서 shiny를 제공하려면, 이전에 설치했던 shinylive 패키지를 사용하여 app.R을 웹페이지로 변환하는 과정이 필요하다.

내 문서(Documents)의 shinylive라는 폴더를 만들고 이 안에 app.R을 저장했을 때를 기준으로, export 함수의 사용 예시는 다음과 같다.

# library(shinylive)
shinylive::export('~/Documents/shinylive', '~/Documents/shinylive_out')

이 코드를 실행하면 shinylive와 동일한 위치, 즉 내 문서(Documents)에 shinylive_out이라는 폴더를 새롭게 만들고 그 안에 shinylive 패키지를 사용해 변환된 wasm 버전의 shiny 코드를 생성한다.

이 shinylive_out 폴더의 내용물을 확인해보면 다음과 같으며 이전 글에서 언급했던 webr, serviceworker 등이 포함되어 있는 것을 확인할 수 있다.

조금 더 구체적으로 export 함수는 현재 R studio를 실행하고 있는 로컬 PC에서 shinylive 패키지의 파일들, 즉 shiny와 관련된 라이브러리 파일들을 out 디렉토리에 추가하는 역할을 한다.

이제 이 폴더의 내용물을 기준으로 github page등을 만들면 shiny 를 제공하는 정적인 웹페이지를 제공할 수 있으며 그 결과는 아래의 명령어를 통해 미리 확인해 볼 수 있다.

github page

깃허브 페이지 배포를 위해서는 이전에 작성했던 pkgdown의 글 을 참고하길 권장하며, 이를 위해 shinylive_out 대신 docs 폴더로 결과를 내보내길 권장한다.

httpuv::runStaticServer("~/Documents/shinylive_out")

shinylive in Quarto

quarto 블로그에 shiny application을 추가하기 위해서는 별도의 extension을 사용해야한다. quarto extension은 quarto의 기능을 확장하는 별도의 패키지로, 기본 R에 R 패키지를 사용해 기능을 추가하는 것과 유사하다.

먼저 Rstudio의 터미널에서 다음 코드를 실행하여 quarto extenstion을 추가해야 한다.

quarto add quarto-ext/shinylive

quarto 블로그에 shiny 를 심기 위해서 별도의 파일을 만들 필요는 없으며, {shinylive-r}이라는 코드 블록을 사용한다. 추가로 index.qmd의 yaml에 shinylive 를 설정해야만 한다.

filters: 
  - shinylive

이후 shinylive-r 블록에 앞서 만든 app.R 의 내용을 작성한다.

```{shinylive-r}
#| standalone: true
#| viewerHeight: 800

library(shiny)

ui <- fluidPage(
  titlePanel("Hello Shiny!"),
  sidebarLayout(
    sidebarPanel(
      sliderInput(
        inputId = "bins",
        label = "Number of bins:",
        min = 1,
        max = 50,
        value = 30
      )
    ),
    mainPanel(
      plotOutput(outputId = "distPlot")
    )
  )
)

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"
    )
  })
}

shinyApp(ui = ui, server = server)
```

아래는 실제 코드 블록이 어플리케이션으로 실행되는 결과이며 slider를 움직일때 반응하여 histogram을 그리는 것을 확인할 수 있다.

#| standalone: true
#| viewerHeight: 800

library(shiny)

ui <- fluidPage(
  titlePanel("Hello Shiny!"),
  sidebarLayout(
    sidebarPanel(
      sliderInput(
        inputId = "bins",
        label = "Number of bins:",
        min = 1,
        max = 50,
        value = 30
      )
    ),
    mainPanel(
      plotOutput(outputId = "distPlot")
    )
  )
)

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"
    )
  })
}

shinyApp(ui = ui, server = server)

정리

shinylive는 wasm을 활용해 깃허브 페이지 또는 quarto 블로그 같은 정적 페이지에서 shiny를 실행할 수 있게 하는 기능으로 각각 R 패키지와 quarto extension을 통해 사용할 수 있다.

물론 아직 나온지 1년이 되지 않은 기능인만큼 모든 기능이 제공되는 것은 아니며 정적 페이지를 사용하는 만큼 별도의 shiny server를 활용하는 것에 비하면 단점이 있기도 하다.

그러나 shiny 사용법이나 간단한 통계 분석을 소개하고, 이를 웹사이트에서 별도의 R 설치 없이도 바로 실습할 수 있다는 점에서 많이 사용되고 있으며 앞으로도 더 많은 기능이 추가될 것으로 기대된다.

이 블로그에 사용한 코드는 링크에서 확인할 수 있다.

Reuse

Citation

BibTeX citation:
@online{kim2024,
  author = {Kim, Jinhwan},
  title = {Shinylive {를} {활용한} Quarto {블로그에} Shiny {추가}
    {방법}},
  date = {2024-03-05},
  url = {https://blog.zarathu.com/posts/2024-03-04-shinylive},
  langid = {en}
}
For attribution, please cite this work as:
Kim, Jinhwan. 2024. “Shinylive 를 활용한 Quarto 블로그에 Shiny 추가 방법.” March 5, 2024. https://blog.zarathu.com/posts/2024-03-04-shinylive.