Search code examples
rshinyr-package

In R package workflow how to add image to shiny app


I have problems to understand this behavior:

I have a small shiny app organized in a package workflow like described here:

  1. Put all R code in the R/ directory.
  2. Write a function that starts your app (i.e. calls shinyApp() with your UI and server).
  3. Create a DESCRIPTION file in the root directory of your app.

Here is a minimal reproducible example:

library(shiny)

myApp <- function(...) {
  
  ui <- fluidPage(
    titlePanel("Minimal Shiny App"),
    
    mainPanel(
      div(
        style = "display: flex; align-items: center;",
        sliderInput("slider", "Slider", min = 1, max = 10, value = 5),
        tags$img(src = "logo.png", width = 200, style = "margin-left: 20px;")
      ),
      plotOutput("plot")
    )
  )
  
  server <- function(input, output) {
    output$plot <- renderPlot({
      plot(1:input$slider, type = "l", lwd = 2)
    })
  }
  
  shinyApp(ui = ui, server = server, ...)
}

myApp()

I would like to add the logo.png image to the app:

1. Using this code, I get this:

library(devtools)
load_all()
myApp()

enter image description here

2. Using this code once, I get this:

runApp()

enter image description here

3. If I use now myApp() (after I have used runApp() once in the app), I get this:

# After I used runApp() once before
myApp()

enter image description here

The logo.png file is in www folder in the R folder.

All works fine if I do not use the package workflow. But I need this workflow and for me it is not possible to get the image there when using load_all() and myApp().

I have used system.file like tags$img(src = system.file("R/www", "logo.png", package = "test2"), width = 200, style = "margin-left: 20px;")) but same behaviour


Solution

  • A good approach would be "Create a package which contains an R Shiny app".

    Let's call the package "rabbit". This is my suggested file & folder arrangement:

    |- .Rbuildignore
    |- .Renviron
    |- .Rprofile
    |- data/
    |- data-raw/
    |- DESCRIPTION
    |- rabbit.Rproj
    |- inst/
        |- app/
            |- global.R
            |- R/
            |- server.R
            |- ui.R
            |- www/
    |- NAMESPACE
    |- R/
    |- README.md
    |- README.Rmd
    |- tests/
    

    You don't need to have all the files/folders listed above.

    Now let's look at the important directories in regards to your question.

    R/

    This is the one at the root of the project folder (listed after NAMESPACE above).

    Put all the business logic there. These are the functions which can be exported from your package. These have nothing to do with the app.

    It will also contain run_rabbit.R which is a function to run your app.

    #' Run the rabbit shiny app
    #' 
    #' @export
    run_rabbit <- function() {
      # You can set options for your app here, eg.
      # Increase file upload size to 1GB:
      # options(shiny.maxRequestSize = 1e3 * 1024^2)
      
      app_dir <- system.file("app", package = "rabbit")
      if (app_dir == "") {
        stop(
          "Could not find the app directory. Try re-installing `rabbit`.",
          call. = FALSE
        )
      }
      setwd(app_dir)
      shiny::shinyAppDir(appDir = ".")
    }
    

    inst/app/R/

    This is where your shiny modules and other helper functions related to the app will reside.

    inst/app/www/

    You can put your CSS, JS and image files here.

    To reference these in the app, you can:

    tags$link(rel = "stylesheet", href = "styles.css")
    

    Say you decide to put all images in one folder inst/app/www/img/, then you can:

    tags$img(
      src = file.path('img', 'rabbit-logo.svg')
    )
    

    where rabbit-logo.svg is your app's logo.

    Run the app

    devtools::load_all()
    run_rabbit()