Output a dynamic number of photos onto a ShinyApp UI?

Hello!

I've been successful at using renderImage() function to output one image file to the UI, but I was wondering if there was any way to draw a dynamic amount of photos and stack them all on top of each other in the UI main panel. The background algorithm of my app generates a folder of output images, and I was wondering if anyone knew of a way to loop through that folder and stack the images in the UI. I'm not sure how many images will be produced since it depends on the input and is generated reactively when the input is submitted.

Thanks for any insight you can share!

This seems to work. I've modified the stock shiny app and used shinyFiles to select the image files into paths which you can replace with path names to your images using your favourite approach.

library(shiny)
library(shinyFiles)
library(purrr)


ui <- fluidPage(
  
  titlePanel("My Images"),
  
  sidebarLayout(
    
    # Choose the images
    sidebarPanel(
      shinyFilesButton(
        'files'
        , label='File select'
        , title='Please select a file'
        , multiple=TRUE
      )
    ),
    
    # Show the images
    mainPanel(
      uiOutput('images')
    )
  )
)

# Define server logic required to draw a histogram
server <- function(input, output, session) {
  
  shinyFileChoose(
    input,
    'files',
    roots = getVolumes(),
    session = session,
    restrictions = system.file(package = 'base')
  )
  
  output$images <- renderUI({
    
    files <- input$files
    has_root <- "root" %in% names(files)
    validate(need(has_root, "Choose files"))
    
    root <- files$root
    root <- "C:" # root returns an unusable value that causes errors
    paths <- files[[1]] %>% map_chr(~file.path(root, .x[[2]], .x[[3]]))
    
    paths %>% map(
      function(path){
        renderImage(
          list(
            src = path
            , alt = "Can't show file!"
            , width = 500
            , height = 300
          )
          , deleteFile = FALSE)
      }
    )
    
    
  })
}

# Run the application 
shinyApp(ui = ui, server = server)

1 Like

The slickr library could also be useful, instead of showing all the plots at once you can scroll through the results.
https://cran.r-project.org/web/packages/slickR/vignettes/basics.html
https://cran.r-project.org/web/packages/slickR/vignettes/shiny.html

1 Like

Welcome to the community @Couth! In addition to the previous responses, here is another way to stack a selected number of images in a shiny UI.

Within the folder where the shiny app .R file is located, I saved 10 identical images (Posit logo) within a folder named www. The code below first gathers the image filepaths via list.files, specifying the www folder. Then, within a renderUI call in the server, if the number selected is greater than 0, an HTML text statement is generated for the number of images selected. The images are stacked by including a break tag (<br>) at the end of the HTML statement.

library(shiny)

# get filepaths for all images in the wwww folder
my_images = list.files('www', full.names = F, pattern = '.PNG')

ui <- fluidPage(
  br(),
  selectInput('number', 
              'Select the number of images to show', 
              choices = 0:length(my_images),
              multiple = F
              ),
  br(),
  uiOutput('images')
  
)

server <- function(input, output, session) {
  
  output$images = renderUI({
    req(input$number)
    
    # show image(s) if 1 or more is selected
    if(input$number > 0) {
      
      display_image = function(i) {
        HTML(paste0('<img src = ', my_images[i], ' style="margin-top: 5px;"><br>'))
      }
      
      lapply(1:input$number, display_image)
    }
  })
  
}

shinyApp(ui, server)

1 Like

This topic was automatically closed 54 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.