Search code examples
rmodulepackager-packageshinymodules

How to include and display images in R package?


I am trying to package a Shiny module that displays a modal with a logo (in png format). For this purpose, I have created a "inst/www" directory to store the logo file. The directory tree looks something like this:

├─ DESCRIPTION
├─ inst
│   └── www
│       └── logo.png
├── man
│   └── test.Rd
├── NAMESPACE
├── packagetest.Rproj
└── R
    └── test.R

However, after building and installing, the package doesn't seem to read from the predefined directory where I put my "logo.png". Instead, it reads from the main project where I inserted the function from the package. The testUI() function of the package is something like this:

testUI <- function(id) {
  ns <- NS(id)

  shiny::showModal(
    modalDialog(
      title = img(src="inst/www/logo.png", style="display:block; margin-left:auto; margin-right:auto;"),
      br(),
      fluidRow(
        column(6, align="center", offset = 3,
               textInput(ns("username"), label = NULL, placeholder = "Username"),
               passwordInput(ns("password"), label = NULL, placeholder = "Password")
        )
      ),
      footer = (
        fluidRow(
          column(6, align="center", offset = 3,
                 actionButton(ns("signin"),"Sign in")
          )
        )
      )
    )
  )
}

From what I've seen in other projects, the "inst" folder seems to be the way to go but I'm still new to R packages so I don't really know what I'm doing. Any help on this is much appreciated, thanks!


Solution

  • ...and almost a year later, I found the answer to my question while working on an actual package that needs to include image assets! According to the official R package documentation section on the inst folder:

    To find a file in inst/ from code use system.file(). For example, to find inst/extdata/mydata.csv, you’d call system.file("extdata", "mydata.csv", package = "mypackage"). Note that you omit the inst/ directory from the path. This will work if the package is installed, or if it’s been loaded with devtools::load_all().

    In this case, assuming my package is called "testpackage":

    testUI <- function(id) {
      ns <- NS(id)
    
      shiny::showModal(
        modalDialog(
          title = img(
                    src=system.file("www/logo.png", package = "testpackage"),
                    style="display:block; margin-left:auto; margin-right:auto;"
          ),
          br(),
          fluidRow(
            column(6, align="center", offset = 3,
                   textInput(ns("username"), label = NULL, placeholder = "Username"),
                   passwordInput(ns("password"), label = NULL, placeholder = "Password")
            )
          ),
          footer = (
            fluidRow(
              column(6, align="center", offset = 3,
                     actionButton(ns("signin"),"Sign in")
              )
            )
          )
        )
      )
    }
    

    Note that I didn't use the comma separated directory structure as shown in the official example as I found that it's more intuitive to enter the full relative path, keeping in mind that:

    When a package is installed, everything in inst/ is copied into the top-level package directory. In some sense inst/ is the opposite of .Rbuildignore - where .Rbuildignore lets you remove arbitrary files and directories from the top level, inst/ lets you add them. You are free to put anything you like in inst/ with one caution: because inst/ is copied into the top-level directory, you should never use a subdirectory with the same name as an existing directory. This means that you should avoid inst/build, inst/data, inst/demo, inst/exec, inst/help, inst/html, inst/inst, inst/libs, inst/Meta, inst/man, inst/po, inst/R, inst/src, inst/tests, inst/tools and inst/vignettes.

    Hope this helps anyone else that's facing the same issue :)