I have an app that shows data as well as a picture based on user input. I have the following code in my ui:
selectInput("var",
label = "Choose a penguin to display",
choices = c("Bowie", "Cookie",
"Mango", "Renesme"),
selected = "Bowie"),
dateRangeInput("dates",
"Date range",
start = "2017-06-16",
end = as.character(Sys.Date())),
imageOutput("img1")
),
mainPanel(plotOutput("plot")
)
)
))
And the following in my server:
output$plot <- renderPlot({
penguin <- switch(input$var,
"Bowie" = filter(date_swim, penguin == 'Bowie'),
"Cookie" = filter(date_swim, penguin == 'Cookie'),
"Mango" = filter(date_swim, penguin == 'Mango'),
"Renesme" = filter(date_swim, penguin == 'Renesme'))
getSwim(min = input$dates[1],
max = input$dates[2],
p = penguin)
})
output$img1 <- renderImage({ #This is where the image is set
if(input$var == "Bowie"){
img(src = "Bowie.png", height = 240, width = 300)
}
else if(input$var == "Cookie"){
img(src = "Cookie.png", height = 240, width = 300)
}
else if(input$var == "Renesme"){
img(src = "Renesme.png", height = 240, width = 300)
}
else if(input$var == "Mango"){
img(src = "Mango.png", height = 240, width = 300)
}
})
})
When I run, where the image should be I see the error message:
character argument vector expected.
I think this is a bit misleading in the docs but for RenderImage() you want to use list() function and not img(). I reworked your server.R file a bit:
download.file("http://dehayf5mhw1h7.cloudfront.net/wp-content/uploads/sites/38/2016/01/18220900/Getty_011816_Bluepenguin.jpg",
destfile = "Bowie.png")
download.file("http://3.bp.blogspot.com/_cBH6cWZr1IU/TUURNp7LADI/AAAAAAAABsY/76UhGhmxjzY/s640/penguin+cookies_0018.jpg",
destfile = "Cookie.png")
function(input, output) {
output$img1 <- renderImage({ #This is where the image is set
if(input$var == "Bowie"){
list(src = "Bowie.png", height = 240, width = 300)
}
else if(input$var == "Cookie"){
list(src = "Cookie.png", height = 240, width = 300)
}
else if(input$var == "Renesme"){
list(src = "Renesme.png", height = 240, width = 300)
}
else if(input$var == "Mango"){
list(src = "Mango.png", height = 240, width = 300)
}
})
Related
I have a shiny app to load pictures and I should be able to select some of the images by clicking on them and the selected images will be recorded.
I want a function that I can select and mark pictures the same way you mark photos in the gallery of a phone.
Currently, I made an app that the selected images are replaced by an empty icon. Here is what I have tried:
ui <-fluidPage(column(
width=9,
align="center",
imageOutput(outputId = "img1", click = clickOpts(id = "img1_click", clip = FALSE),width = 150,height = 150,inline = TRUE)
,imageOutput(outputId = "img2", click = clickOpts(id = "img2_click", clip = FALSE),width = 150,height = 150,inline = TRUE)
))
server <- function(input, output, session) {
empty_img="/empty.jpeg"
vals=reactiveValues(img=list.files("/images/"))
vals2=reactiveValues(img=list.files("/images/"))
empty_img_to_normal_value=reactiveValues(m=1:length(vals$img))
output$img1 <- renderImage({
list(src = vals$img[1], width = "200", height = "200") } ,deleteFile = FALSE)
observeEvent(input$img1_click, {
if(empty_img_to_normal_value$m[1]==1){
vals$img[1]=empty_img
empty_img_to_normal_value$m[1]=0
}else{
vals$img[1]=vals2$img[1]
empty_img_to_normal_value$m[1]=1
}
})
output$img2 <- renderImage({
list(src = vals$img[2], width = "200", height = "200")} ,deleteFile = FALSE)
observeEvent(input$img2_click, {
if(empty_img_to_normal_value$m[2]==1){
vals$img[2]=empty_img
empty_img_to_normal_value$m[2]=0
}else{
vals$img[2]=vals2$img[2]
empty_img_to_normal_value$m[2]=1
}
})
}
Following our comments, I made a proper answer.
# list of images URLs, replace them with your images
lst_urls <- list("data/Rplot1.png", "data/Rplot1.png", "data/Rplot1.png", "data/Rplot1.png",
"data/Rplot5.png","data/Rplot5.png","data/Rplot5.png","data/Rplot5.png")
img_w <- "100%"
img_h <- 200
mod_img_UI <- function(id) {
ns <- NS(id)
tagList(
tags$style(".checkbox{margin-bottom: -40px;}"),
column(
width =2,
checkboxInput(
inputId = ns("select_img"), label = NULL
),
imageOutput(
outputId = ns("img"), width = img_w, height = img_h, inline = TRUE
)
)
)
}
mod_img_SERVER <- function(input, output, session, img_url){
ns <- session$ns
output$img <- renderImage({
list(src = img_url,
alt = "This is alternate text",
width = img_w,
height = img_h,
contentType = "image/png")
}, deleteFile = FALSE)
return(input$select_img)
}
ui <- fluidPage(
uiOutput("images")
)
server <- function(input, output, session) {
output$images <- renderUI({
lapply(
1:length(lst_urls),
function(i) {
mod_img_UI(id = paste0("img", i))
}
)
})
observe({
selected_imgs <- lapply(
1:length(lst_urls),
function(i) {
callModule(
module = mod_img_SERVER,
session = session,
id = paste0("img", i),
img_url = lst_urls[[i]]
)
}
)
print(paste("You picked :",lst_urls[unlist(selected_imgs)]))
})
}
shinyApp(ui, server)
I am able to use zoom on a single image, and that works well. However, in a more complex app, I have a dynamic UI that the plotting depends on a selectInput() like this:
output$all <- renderUI({
if (input$choice == 'two nodes') {
uiOutput("two")
}else{
uiOutput("three")
}
})
The problem is that when the user switches to the new visualisation, the zooming function stops working. (I have tried changing the 100ms but that's not the issue)
Here is a reproducible example:
library(shiny)
library(DiagrammeR)
library(magrittr)
js <- '
$(document).ready(function(){
var instance;
var myinterval = setInterval(function(){
var element = document.getElementById("grr");
if(element !== null){
clearInterval(myinterval);
instance = panzoom(element);
}
}, 100);
});
'
js2 <- '
$(document).ready(function(){
var instance;
var myinterval = setInterval(function(){
var element = document.getElementById("grr2");
if(element !== null){
clearInterval(myinterval);
instance = panzoom(element);
}
}, 100);
});
'
ui <- fluidPage(
selectInput('choice',
'choices:',choices = c('two nodes','three nodes')),
tags$head(
tags$script(src = "https://unpkg.com/panzoom#9.4.0/dist/panzoom.min.js"),
tags$script(HTML(js)),
tags$script(HTML(js2))
),
uiOutput("all")
)
server <- function(input, output) {
output$two_nodes <- renderUI({
div(
grVizOutput("grr", width = "100%", height = "90vh")
)
})
output$three_nodes <- renderUI({
div(
grVizOutput("grr2", width = "100%", height = "90vh")
)
})
output$all <- renderUI({
if (input$choice == 'two nodes') {
uiOutput("two_nodes")
}else{
uiOutput("three_nodes")
}
})
output$grr <- renderGrViz(render_graph(
create_graph() %>%
add_n_nodes(n = 2) %>%
add_edge(
from = 1,
to = 2,
edge_data = edge_data(
value = 4.3
)
)
))
output$grr2 <- renderGrViz(render_graph(
create_graph() %>%
add_n_nodes(n = 3) %>%
add_edge(
from = 1,
to = 2,
edge_data = edge_data(
value = 4.3
)
)
))
}
shinyApp(ui, server)
Since you used renderUI, we can add panzoom after grVizoutput, like this
library(shiny)
library(DiagrammeR)
library(magrittr)
library(shinyWidgets)
ui <- fluidPage(
selectInput('choice',
'choices:',choices = c('two nodes','three nodes')),
tags$head(
tags$script(src = "https://unpkg.com/panzoom#9.4.0/dist/panzoom.min.js"),
# tags$script(HTML(js))
),
uiOutput("all")
)
server <- function(input, output) {
output$two_nodes <- renderUI({
div(
grVizOutput("grr", width = "100%", height = "90vh"),
tags$script(HTML('panzoom($(".grViz").get(0))')),
actionGroupButtons(
inputIds = c("zoomout", "zoomin", "reset"),
labels = list(icon("minus"), icon("plus"), "Reset"),
status = "primary"
)
)
})
output$three_nodes <- renderUI({
div(
grVizOutput("grr2", width = "100%", height = "90vh"),
tags$script(HTML('panzoom($(".grViz").get(0))')),
actionGroupButtons(
inputIds = c("zoomout", "zoomin", "reset"),
labels = list(icon("minus"), icon("plus"), "Reset"),
status = "primary"
)
)
})
output$all <- renderUI({
if (input$choice == 'two nodes') {
uiOutput("two_nodes")
}else{
uiOutput("three_nodes")
}
})
output$grr <- renderGrViz(render_graph(
create_graph() %>%
add_n_nodes(n = 2) %>%
add_edge(
from = 1,
to = 2,
edge_data = edge_data(
value = 4.3
)
)
))
output$grr2 <- renderGrViz(render_graph(
create_graph() %>%
add_n_nodes(n = 3) %>%
add_edge(
from = 1,
to = 2,
edge_data = edge_data(
value = 4.3
)
)
))
}
shinyApp(ui, server)
is there any way in R, shinydashboard, to render multiple images in the dashboard body based on the selectinput option?
Here are my codes:
library(shiny)
library(shinydashboard)
images_a <- list.files("input/plots 1/", pattern = ".png") # 6 'png' images are in the *input/plots 1* folder
images_b <- list.files("input/plots 1/", pattern = ".jpg") # 5 'jpg' images are in the *input/plots 1* folder
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(selectInput(inputId = "image_type", label = "Image type", choices = c("png", "jpg"), selected = "png")),
dashboardBody()
)
server <- function(input, output) {
}
shinyApp(ui, server)
Thank you!
Use lapply( ) to loop through in renderImage( )
download.file("http://dehayf5mhw1h7.cloudfront.net/wp-content/uploads/sites/38/2016/01/18220900/Getty_011816_Bluepenguin.jpg",
destfile = "Bowie.png")
download.file("http://3.bp.blogspot.com/_cBH6cWZr1IU/TUURNp7LADI/AAAAAAAABsY/76UhGhmxjzY/s640/penguin+cookies_0018.jpg",
destfile = "Cookie.png")
function(input, output) {
output$img1 <- renderImage({ #This is where the image is set
if(input$var == "Bowie"){
list(src = "Bowie.png", height = 240, width = 300)
}
else if(input$var == "Cookie"){
list(src = "Cookie.png", height = 240, width = 300)
}
else if(input$var == "Renesme"){
list(src = "Renesme.png", height = 240, width = 300)
}
else if(input$var == "Mango"){
list(src = "Mango.png", height = 240, width = 300)
}
})
New to shiny and struggling with this for more than two days now.
I have created an application where the user loads .csv data file and chooses one or more variables whose names appear in the application as check boxes. When a checkbox is checked, a new checkbox appears under with the same name and when it is clicked too, a textAreaInput appears next to it where the user can add variable names that constitute the target variable as a scale. Here is an oversimplified version of the application:
library(shiny)
ui <- fluidPage(
mainPanel(
fileInput(inputId = "file", label = "Choose File", multiple = TRUE, accept = ".csv"),
uiOutput(outputId = "varCheckBoxesIndivScores"),
column(width = 3,
uiOutput(outputId = "selectedScoresCheckBoxes")),
conditionalPanel(condition = "input.selectedScoresCheckBoxes",
column(width = 6,
uiOutput(outputId = "variablesConstitutingScale"))
)
)
)
server = function(input, output, session) {
df <- reactive({
if(is.null(input$file)) {
return(NULL)
} else {
tbl <- fread(input$file$datapath, stringsAsFactors = TRUE)
return(tbl)
}
})
output$varCheckBoxesIndivScores <- renderUI({
if(is.null(df())) {
return(NULL)
} else if(!is.null(df())) {
return(tags$div(align = "left",
class = "multicol",
checkboxGroupInput(inputId = "varCheckBoxesIndivScores",
label = "Select variables",
choices = colnames(df()))))
}
})
output$selectedScoresCheckBoxes <- renderUI({
if(is.null(df())) {
return(NULL)
} else if(!is.null(df())) {
return(tags$div(align = "left",
checkboxGroupInput(inputId = "selectedScoresCheckBoxes",
label = "",
choices = input$varCheckBoxesIndivScores)))
}
})
output$variablesConstitutingScale <- renderUI({
if(is.null(df())) {
return(NULL)
} else if(!is.null(df()) & length(input$selectedScoresCheckBoxes > 0)) {
var.list.input.fields <- lapply(input$selectedScoresCheckBoxes, function(i) {
textAreaInput(inputId = "i", label = paste("Variables constituting scale", i), width = "700px", height = "100px", value = NULL)
})
var.list.input.fields
}
})
}
shinyApp(ui = ui, server = server)
The data to load is generated like this (just an excerpt, the real one has more columns and cases):
library(data.table)
x <- data.table(ID = c(2201:2220), VAR1 = rnorm(n = 20, mean = 10, sd = 2),
VAR2 = rnorm(n = 20, mean = 100, sd = 20), VAR3 = 1:20, VAR4 = 21:40,
VAR5 = 41:60, VAR6 = 61:80, VAR7 = 81:100)
write.csv(x = x, file = "/tmp/test_data.csv", row.names = FALSE)
It works fine, no errors. Here is how it looks, after I enter the variable names in each of the generated textAreaInput fields:
However, I would like to take the user input from each dynamically generated textAreaInput and store it in a list like:
list(VAR1 = "VAR3 VAR4 VAR5", VAR2 = "VAR6 VAR7")
or
list(VAR1 = "VAR3", "VAR4", "VAR5", VAR2 = "VAR6", "VAR7")
inside the server part of the application for future use.
I tried to follow the solution in this thread, but I did not succeed to come to any solution and feel quite confused. Can someone help?
First, you want to make sure to assign each of your dynimcally added elements to have a unique name. You have just hard coded the letter "i" in the sample. You want something like
textAreaInput(inputId = paste0("varconst_",i), label = paste("Variables constituting scale", i),
width = "700px", height = "100px", value = NULL)
Then you can observe those text boxes with something like this
observeEvent(lapply(paste0("varconst_", input$selectedScoresCheckBoxes), function(x) input[[x]]), {
obj <- Map(function(x) input[[paste0("varconst_",x)]], input$selectedScoresCheckBoxes)
dput(obj)
})
Here I just used dput to dump the list to the console so you can see it as it gets updated but you can do whatever you want with that.
I have modified the code of the application as per MrFlick's answer. To leave a paper trail of the complete solution, I am posting it below. The few additional modifications I have made include the printout of the list with the variables for each of the generated textAreaInput fields, so that the list can be viewed in the application itself. I have also added some further modifications of the obj, after it is generated, to obtain the list as desired.
If there are more dynamically generated output sections where check boxes and related text areas, the varconst_ index has to be made unique across the different chunks of code (e.g. varconst1_, varconst2_, varconst3_, etc.).
Here is the code:
library(shiny)
ui <- fluidPage(
mainPanel(
fileInput(inputId = "file", label = "Choose File", multiple = TRUE, accept = ".csv"),
uiOutput(outputId = "varCheckBoxesIndivScores"),
fluidRow(
column(width = 3,
uiOutput(outputId = "selectedScoresCheckBoxes")),
conditionalPanel(condition = "input.selectedScoresCheckBoxes",
column(width = 6,
uiOutput(outputId = "variablesConstitutingScale")))),
br(),
fluidRow(
conditionalPanel(condition = "input.selectedScoresCheckBoxes",
verbatimTextOutput(outputId = "scalesVarList")))
)
)
server = function(input, output, session) {
df <- reactive({
if(is.null(input$file)) {
return(NULL)
} else {
tbl <- fread(input$file$datapath, stringsAsFactors = TRUE)
return(tbl)
}
})
output$varCheckBoxesIndivScores <- renderUI({
if(is.null(df())) {
return(NULL)
} else if(!is.null(df())) {
return(tags$div(align = "left",
class = "multicol",
checkboxGroupInput(inputId = "varCheckBoxesIndivScores",
label = "Select variables",
choices = colnames(df()))))
}
})
output$selectedScoresCheckBoxes <- renderUI({
if(is.null(df())) {
return(NULL)
} else if(!is.null(df())) {
return(tags$div(align = "left",
checkboxGroupInput(inputId = "selectedScoresCheckBoxes",
label = "",
choices = input$varCheckBoxesIndivScores)))
}
})
output$variablesConstitutingScale <- renderUI({
if(is.null(df())) {
return(NULL)
} else if(!is.null(df()) & length(input$selectedScoresCheckBoxes > 0)) {
var.list.input.fields <- lapply(input$selectedScoresCheckBoxes, function(i) {
textAreaInput(inputId = paste0("varconst_",i), label = paste("Variables constituting scale", i),
width = "700px", height = "100px", value = NULL)
})
var.list.input.fields
}
})
observeEvent(lapply(paste0("varconst_", input$selectedScoresCheckBoxes), function(x) input[[x]]), {
obj <- Map(function(x) input[[paste0("varconst_",x)]], input$selectedScoresCheckBoxes)
obj <- sapply(obj, function(i) {
if(length(i) > 0) {
strsplit(x = i, split = " ")
}
})
dput(obj)
output$scalesVarList <- renderPrint({
if(is.null(df())) {
return(NULL)
} else if(!is.null(df()) && length(input$selectedScoresCheckBoxes) > 0 && length(obj) > 0) {
print(obj)
}
})
})
}
shinyApp(ui = ui, server = server)
I am just learning R Shiny and have been playing around with the various examples in the gallery. For the "Image Output" example:
http://shiny.rstudio.com/gallery/image-output.html
I was wondering how I might be able to include an image headline when I select either the chainring or smiley radio button. For example after selecting "smiley" I would like the title "Smiley" to display below the image. Thank you for your help. Below is the code that is also included in the link above. (Some of it was intentionally deleted for clarity). Thank you
library(png) # For writePNG function
shinyServer(function(input, output, session) {
# A temp file to save the output.
# This file will be automatically removed later by
# renderImage, because of the deleteFile=TRUE argument.
outfile <- tempfile(fileext = ".png")
# Generate the image and write it to file
x <- matrix(rep((0:(width-1))/(width-1), height), height,
byrow = TRUE)
y <- matrix(rep((0:(height-1))/(height-1), width), height)
pic <- gauss2d(x, y, input$r)
writePNG(pic, target = outfile)
# Return a list containing information about the image
list(src = outfile,
contentType = "image/png",
width = width,
height = height,
alt = "This is alternate text")
}, deleteFile = TRUE)
# image2 sends pre-rendered images
output$image2 <- renderImage({
if (is.null(input$picture))
return(NULL)
if (input$picture == "face") {
return(list(
src = "images/face.png",
contentType = "image/png",
alt = "Face"
))
} else if (input$picture == "chainring") {
return(list(
src = "images/chainring.jpg",
filetype = "image/jpeg",
alt = "This is a chainring"
))
}
}, deleteFile = FALSE)
})
shinyUI(fluidPage(
titlePanel("Client data and query string example"),
fluidRow(
column(4, wellPanel(
sliderInput("r", "Radius :", min = 0.05, max = 1,
value = 0.2, step = 0.05),
radioButtons("picture", "Picture:",
c("chainring", "face"))
)),
column(4,
imageOutput("image1", height = 300),
imageOutput("image2")
)
)
Does this help?
ui.R
library(shiny)
shinyUI(fluidPage(
titlePanel("Image title"),
sidebarLayout(
sidebarPanel(
sliderInput("obs", "Number of observations:",
min = 0, max = 1000, value = 500)
),
mainPanel(
imageOutput("myImage"),
uiOutput("text")
)
)
))
server.R
library(shiny)
shinyServer(function(input, output) {
output$myImage <- renderImage({
outfile <- tempfile(fileext='.png')
png(outfile, width=400, height=300)
hist(rnorm(input$obs), main = "")
dev.off()
list(src = outfile,
contentType = 'image/png',
width = 400,
height = 300,
alt = "This is alternate text")
}, deleteFile = TRUE)
histogramTitle <- reactive({
paste("<h5>", input$obs, " observation used to create the histogram</h5>", sep = "")
})
output$text <- renderUI({
HTML(as.character(histogramTitle()))
})
})