I am trying to plot several images saved in the www sub-directory folder of my shiny app folder. The image file names are in a data frame column; let’s say “img_path”. I am using the imageOutput() function in the UI and renderImage() in the server interface. Since I want to plot all the images in the www subfolder and that are referenced in the data frame, I am using a for loop. Unfortunately, instead of rendering all the images, it always displays the last image. I guess this is happening because images are being overlayed on top of each other. How do you solve this problem?
Let say that I have: my data
df_img <- data.frame(id = c(1:5), img_path = c("h1000.png", "h2000.png", "h3000.png", "h4000.png", "h000.png"))
which is stored in the data subfolder; the 5 images in the www subfolder are named as in the df_img[["img_path"]]
.
My basic shiny app code is:
library(shiny)
library(shinydashboard)
Define UI
ui <- fluidPage(
# Application title
titlePanel("Test app"),
# to render images in the www folder
box(imageOutput("houz"), width = 3)
)
Define server logic
server <- function(input, output) {
df_img <- read.csv("data/df_img.csv", header = T)
for (i in 1:nrow(df_img)) {
output$houz <- renderImage({
list(
src = file.path('www', df_img$img_path[i]),
contentType = "image/jpeg",
width = "100%", height = "45%"
)
}, deleteFile = FALSE)
}
}
# Run the application
shinyApp(ui = ui, server = server)
CodePudding user response:
Consider using Shiny modules. A working example is below, which assumes you have images with a "jpeg" extension in a "www" subdirectory of the working directory. I use purrr
for functional programming - you could use lapply()
or a for
loop if you prefer.
Chapter 19 of Mastering Shiny is a good introduction to Shiny modules.
library(shiny)
library(purrr)
ui_module <- function(id) {
imageOutput(NS(id, "img"))
}
server_module <- function(id,
img_path) {
moduleServer(
id,
function(input, output, session) {
output$img <- renderImage({
list(src = img_path,
contentType = "image/jpeg",
width = "100%",
height = "45%")
},
deleteFile = FALSE)
})
}
images <- list.files(path = "www",
pattern = "jpeg",
full.names = TRUE)
ids <- tools::file_path_sans_ext(
basename(images)
)
ui <- fluidPage(
map(ids, ui_module)
)
server <- function(input, output, session) {
map2(.x = ids,
.y = images,
.f = server_module)
}
shinyApp(ui, server)
CodePudding user response:
You can use renderUI
to display the list of images you wish to display. Try this
df_img <- data.frame(id = c(1:5), img_path = c("h1000.png", "h2000.png", "h3000.png", "h4000.png", "h000.png"))
ui <- fluidPage(
# Application title
titlePanel("Test app"),
# to render images in the www folder
box(uiOutput("houz"), width = 3)
)
server <- function(input, output) {
#df_img <- read.csv("data/df_img.csv", header = T)
n <- nrow(df_img)
observe({
for (i in 1:n)
{
print(i)
local({
my_i <- i
imagename = paste0("img", my_i)
print(imagename)
output[[imagename]] <-
renderImage({
list(src = file.path('www', df_img$img_path[my_i]),
width = "100%", height = "55%",
alt = "Image failed to render")
}, deleteFile = FALSE)
})
}
})
output$houz <- renderUI({
image_output_list <-
lapply(1:n,
function(i)
{
imagename = paste0("img", i)
imageOutput(imagename)
})
do.call(tagList, image_output_list)
})
}
# Run the application
shinyApp(ui = ui, server = server)