I have a folder full of charts, generated from a previous step. All of them are PNG files. I want to be able to choose anyone using Flexdashboard and load it. As no shiny or server service is needed I tried Crosstalk package
library(crosstalk)
library(magrittr)
library(png)
df <- list.files("plots/", full.names = TRUE) %>%
as_tibble() %>%
magrittr::set_names("path")
shared_data <- SharedData$new(df, key = ~path)
p <- shared_data %>% readPNG(source = path)
bscols( filter_select(id = "file_id",
label = "CHOOSE",
sharedData = shared_data,
group = ~path),
p)
I am stuck on a very simple error i cannot solve as all paths are properly read from file:
Error in path.expand(source) : invalid 'path' argument
Tried to use knitr too:
bscols(filter_select("path", "CHOOSE", shared_data),
knitr::include_graphics(shared_data, ~path))
Error in makeGroupOptions(sharedData, group, allLevels) : argument "group" is missing, with no default
Maybe there is a simpler approach but crosstalk seemed a very simple one as it does not need shiny or any other component but a data frame.
AFAIK, If we want the UI to update itself every time new files are added, we will have to use Shiny and its reactive capabilities. The server observes the directory for any new files and asynchronously updates the client's Selectinput every time a new file is added
library(shiny)
########################### Client ###################################
ui <- fluidPage(
titlePanel("Image Viewer"),
sidebarLayout(
sidebarPanel(
selectInput("imgSelect", "Select an image", choices = NULL ),
br(),
),
mainPanel(
imageOutput("imgDisplay")
) #mp
)
)
########################### Server ###################################
server <- function(input, output, session) {
image_dir <- "plots"
oldFiles<- function(){
return( list.files(path=image_dir, pattern = "\\.png$", full.names = TRUE))
}
nowFiles <- function() {
return(list.files(path=image_dir, pattern = "\\.png$", full.names = TRUE))
}
# Constantly poll and check(compare) nowFiles against oldFiles
imgData <- reactivePoll(3000, session, checkFunc = oldFiles ,
valueFunc = nowFiles)
# Update dropdown if files change
observe({
# Retain previous selection when new items are added
curr<- input$imgSelect #gives current selection
if(curr ==''){ curr= imgData()[1] }
# update ui
updateSelectInput(session, "imgSelect", choices = imgData() , selected = curr )
})
# Render new image on selection change
observeEvent(input$imgSelect, {
currImg <- input$imgSelect
#image rendering
output$imgDisplay <- renderImage({
# return list to render image
list(
src = currImg,contentType = 'image/png',
alt = "currImg"
)
}, deleteFile = FALSE)
#end image rendering
})# End observeEvent
}#server
shinyApp(ui, server)
If you place the following lines outside the server()
function, you can share the same file list across multiple sessions
image_dir <- "plots"
imgData <- reactivePoll(3000, session = NULL,
checkFunc = function() {list.files(path=image_dir,
pattern = "\\.png$",
full.names = TRUE)} ,
valueFunc = function() {list.files(path=image_dir,
pattern = "\\.png$",
full.names = TRUE) })
If all you need is a static setup , this still works, and accomplishes it with minimum fuss
```{r}
#
library(stringr)
library(bsselectR)
state_plots <- paste0(list.files("plots", full.names = TRUE, recursive = TRUE))
names(state_plots) <- str_replace_all(state_plots,
c("\\.png" = "",
"plots/" = ""))
bsselect(state_plots, type = "img", selected = "sns_heatmap",
live_search = TRUE, show_tick = TRUE)
```
Output :