I'm trying to tweak the following code to change tabs when any button on data table is clicked. The error message says that a button parameter is missing, which i can't find. My ultimate goal is to use these buttons to filter related data and display in another tab. Please take a look. Thank you for your time.
library(shiny)
library(ggplot2)
library(DT)
library(DBI)
library(shinyjs)
library(shinydashboard)
library(data.table)
library(pool)
library(dplyr)
library(shinyWidgets)
ui <- fluidPage(
title = "Examples of DataTables",
tabsetPanel(
id = 'dataset',
tabPanel("tab 1", DT::dataTableOutput("tab1"), verbatimTextOutput('printMsg')),
tabPanel("tab 2", DT::dataTableOutput("tab2")),
tabPanel("tab 2", DT::dataTableOutput("tab3"))
)
)
server <- function(input, output) {
printText <- reactiveValues(run_id = '')
buttonInput <- function(FUN, len, id, ...) {
inputs <- character(len)
for (i in seq_len(len)) {
inputs[i] <- as.character(FUN(paste0(id, i), ...))
}
inputs
}
vals <- reactiveValues()
#vals$Data <- data.table(
vals$Data <- data.table(
Brands = paste0("Brand", 1:10),
Forecasted_Growth = sample(1:20, 10),
Last_Year_Purchase = round(rnorm(10, 1000, 1000) ^ 2),
Contact = paste0("Brand", 1:10, "#email.com"),
'Lane Summary' = buttonInput(
FUN = actionButton,
len = 10,
id = 'button_',
label = "+",
onclick = 'Shiny.onInputChange(\"lastClick\", this.id)'
)
)
output$tab1 <- DT::renderDataTable({
DT = vals$Data
datatable(DT, escape = F)
})
observeEvent(input$lastClick, {
selectedRow <- as.numeric(strsplit(input$lastClick, "_")[[1]][2])
printText$run_id <<- paste('clicked on ',vals$Data[selectedRow,1])
#change tabs
updateTabsetPanel(session, "dataset",
selected = "tab 2")
})
output$printMsg <- renderText({
printText$run_id
})
}
shinyApp(ui, server)
You need to include session in your server function as an argument, then it works. The use of session is not mandatory due to legacy reasons, but now recommended. In your case, you need it because updateTabsetPanel uses the session object:
library(shiny)
library(ggplot2)
library(DT)
library(shinyjs)
library(shinydashboard)
library(data.table)
library(dplyr)
library(shinyWidgets)
ui <- fluidPage(
title = "Examples of DataTables",
tabsetPanel(
id = 'dataset',
tabPanel("tab 1", DT::dataTableOutput("tab1"), verbatimTextOutput('printMsg')),
tabPanel("tab 2", DT::dataTableOutput("tab2")),
tabPanel("tab 2", DT::dataTableOutput("tab3"))
)
)
server <- function(input, output, session) {
printText <- reactiveValues(run_id = '')
buttonInput <- function(FUN, len, id, ...) {
inputs <- character(len)
for (i in seq_len(len)) {
inputs[i] <- as.character(FUN(paste0(id, i), ...))
}
inputs
}
vals <- reactiveValues()
#vals$Data <- data.table(
vals$Data <- data.table(
Brands = paste0("Brand", 1:10),
Forecasted_Growth = sample(1:20, 10),
Last_Year_Purchase = round(rnorm(10, 1000, 1000) ^ 2),
Contact = paste0("Brand", 1:10, "#email.com"),
'Lane Summary' = buttonInput(
FUN = actionButton,
len = 10,
id = 'button_',
label = "+",
onclick = 'Shiny.onInputChange(\"lastClick\", this.id)'
)
)
output$tab1 <- DT::renderDataTable({
DT = vals$Data
datatable(DT, escape = F)
})
observeEvent(input$lastClick, {
selectedRow <- as.numeric(strsplit(input$lastClick, "_")[[1]][2])
printText$run_id <<- paste('clicked on ',vals$Data[selectedRow,1])
#change tabs
updateTabsetPanel(session, "dataset",
selected = "tab 2")
})
output$printMsg <- renderText({
printText$run_id
})
}
shinyApp(ui, server)
Related
I would like to allow the user to select multiple times the same choice. It implies that when the user selects some element, it should not be removed from the choices' dropdown menu.
Here is a minimal reproducible example:
library(shiny)
ui <- fluidPage(
selectInput(
inputId = "ManyDuplicated",
label = 'SelectInput',
choices = c('Hello', 'World'),
selected = NULL,
multiple = TRUE
)
)
server <- function(input, output) {
}
shinyApp(ui = ui, server = server)
How it is:
How I would like it to be:
What I tried and may be of help:
This code (https://github.com/rstudio/shiny/issues/2939#issuecomment-678269674) works perfectly for a single choice ("^" in the case). However, I can't make it work for more choices (c("^", "a"), for example).
library(shiny)
ui <- fluidPage(
selectInput("x", "choose", c("^" = 1), multiple = TRUE)
)
server <- function(input, output, session) {
observeEvent(input$x, {
choices <- seq_len(length(input$x)+1)
names(choices) <- rep("^", length(choices))
updateSelectInput(session, "x", choices = choices, selected = isolate(input$x))
})
}
shinyApp(ui, server)
With multiple choices it gets a bit more complicated
library(shiny)
my_choices <- c('Hello', 'World')
ui <- fluidPage(
selectInput(
inputId = "ManyDuplicated",
label = 'SelectInput',
choices = my_choices,
selected = NULL,
multiple = TRUE
)
)
server <- function(input, output, session) {
observeEvent(input$ManyDuplicated, {
selected_values <- input$ManyDuplicated
names(selected_values) <- gsub("\\..*", "", selected_values)
print( paste( "Current selection :",
paste( names(selected_values), collapse = ", ")))
number_of_items <- length(input$ManyDuplicated)
new_choices <- paste(my_choices, number_of_items + 1, sep = ".")
names(new_choices) <- my_choices
all_choices <- c(selected_values, new_choices )
updateSelectInput(session, "ManyDuplicated",
choices = all_choices,
selected = isolate(input$ManyDuplicated))
})
}
shinyApp(ui = ui, server = server)
shinyApp(
ui = fluidPage(
selectInput("choose", "Choose",
sort(c("a" = "a1", "b" = "b2")),
multiple = TRUE
)
),
server = function(input, output, session) {
old_choose = c()
old_choices = sort(c("a" = "a1", "b" = "b2"))
idx <- 2
observeEvent(input$choose, {
req(!identical(old_choose, input$choose))
addition <- base::setdiff(input$choose, old_choose)
if (length(addition) > 0) {
idx <<- idx + 1
new_nm <- names(old_choices[old_choices == addition])
new_val <- paste0(new_nm, idx)
choices <- c(old_choices, new_val)
names(choices) <- c(names(old_choices), new_nm)
}
missing <- base::setdiff(old_choose, input$choose)
if (length(missing) > 0) {
missing_idx <- which(old_choices == missing)
choices <- old_choices[-missing_idx]
}
choices <- sort(choices)
updateSelectInput(session, "choose",
choices = choices,
selected = input$choose
)
old_choose <<- input$choose
old_choices <<- choices
}, ignoreNULL = FALSE)
}
)
I currently have a table being generated and I would like the user to be able to create a pdf file when they click the download button.
I am currently getting an error where when I click the download button I get an html file that downloads the entire page of the app. I thought that using pdf(file) would work but it ignores the function.
Here is currently what I have.
library(shiny)
library(xlsx)
library(shinyWidgets)
population <- read.xlsx("population.xlsx", 1)
fieldsMandatory <- c("selectedCountry")
labelMandatory <- function(label) {
tagList(
label,
span("*", class = "mandatory_star")
)
}
appCSS <-
".mandatory_star {color: red;}"
ui <- fluidPage(
navbarPage(title = span("Spatial Tracking of COVID-19 using Mathematical Models", style = "color:#000000; font-weight:bold; font-size:15pt"),
tabPanel(title = "Model",
sidebarLayout(
sidebarPanel(
shinyjs::useShinyjs(),
shinyjs::inlineCSS(appCSS),
div(
id = "dashboard",
pickerInput(
inputId = "selectedCountry",
labelMandatory ("Country"),
choices = population$Country,
multiple = FALSE,
options = pickerOptions(
actionsBox = TRUE,
title = "Please select a country")
),
sliderInput(inputId = "agg",
label = "Aggregation Factor",
min = 0, max = 50, step = 5, value = 10),
actionButton("go","Run Simulation"),
)
),
mainPanel(
tabsetPanel(
tabPanel("Input Summary", verbatimTextOutput("summary"),
tableOutput("table"),
downloadButton(outputId = "downloadSummary", label = "Save Summary"))
)
)
)
)
)
)
server <- function(input, output, session){
observeEvent(input$resetAll, {
shinyjs::reset("dashboard")
})
values <- reactiveValues()
values$df <- data.frame(Variable = character(), Value = character())
observeEvent(input$go, {
row1 <- data.frame(Variable = "Country", Value = input$selectedCountry)
row2 <- data.frame(Variable = "Aggregation Factor", Value = input$agg)
values$df <- rbind(row1, row2)
})
output$table <- renderTable(values$df)
observe({
# check if all mandatory fields have a value
mandatoryFilled <-
vapply(fieldsMandatory,
function(x) {
!is.null(input[[x]]) && input[[x]] != ""
},
logical(1))
mandatoryFilled <- all(mandatoryFilled)
# enable/disable the submit button
shinyjs::toggleState(id = "go", condition = mandatoryFilled)
})
output$downloadSummary <- downloadHandler(
filename = function(file) {
paste('my-report.pdf', )
},
content = function(file) {
pdf(file)
}
)
}
shinyApp(ui,server)
Here's a minimal example:
library(shiny)
ui <- fluidPage(
downloadButton("savepdf", "Save pdf")
)
server <- function(input, output, session) {
output$savepdf <- downloadHandler(
filename = "test.pdf",
content = function(file) {
pdf(file)
plot(iris$Sepal.Length, iris$Sepal.Width)
dev.off()
}
)
}
shinyApp(ui, server)
Also see here.
Here is a minimal example with the package latexpdf. It will create the pdf table in the folder of the app.
library(shiny)
library(latexpdf)
dat <- head(iris, 5)
ui <- fluidPage(
br(),
actionButton("dwnld", "Create pdf"),
tableOutput("mytable")
)
server <- function(input, output, session){
output[["mytable"]] <- renderTable({
dat
})
observeEvent(input[["dwnld"]], {
as.pdf(dat)
})
}
shinyApp(ui, server)
I am trying to add a column of buttons in my datatable that when clicked will pull up a modal but I am having trouble using the examples I found online here and here.
Some of my requirements:
Needs to work with an unknown number of rows in the dataset (could be 5, could be 10, could be 500)
Each button needs to be unique id which I can use to reference the row (in the example you can see I am pulling in the row number into the modal - real life I am using the row number to subset my data and actually put information in the modal)
Code:
library(shiny)
library(shinydashboard)
library(DT)
ui = dashboardPage(
dashboardHeader(),
dashboardSidebar(),
dashboardBody(
DTOutput('x1'),
verbatimTextOutput("test")
)
)
server = function(input, output) {
##DATA TABLE WHERE I NEED A BUTTON##
output$x1 = renderDT(
iris,
selection = 'single',
options = list(
)
)
##MODAL CALLED BASED ON BUTTON CLICK
observeEvent(input$x1_cell_clicked, {
row = input$x1_cell_clicked$row
if (is.null(row) || row == '') {} else{
showModal(modalDialog(
title = paste0("Timeline!",row),
size = "s",
easyClose = TRUE,
footer = NULL
))
}
})
output$test <- renderPrint({
input$x1_cell_clicked$row
})
}
shinyApp(ui, server)
In your comment, you asked for the case of multiple datatables. Is it what you want ?
library(shiny)
library(DT)
button <- function(tbl){
function(i){
sprintf(
'<button id="button_%s_%d" type="button" onclick="%s">Click me</button>',
tbl, i, "Shiny.setInputValue('button', this.id);")
}
}
dat1 <- cbind(iris,
button = sapply(1:nrow(iris), button("tbl1")),
stringsAsFactors = FALSE)
dat2 <- cbind(mtcars,
button = sapply(1:nrow(mtcars), button("tbl2")),
stringsAsFactors = FALSE)
ui <- fluidPage(
fluidRow(
column(
width = 6,
DTOutput("tbl1", height = "500px")
),
column(
width = 6,
DTOutput("tbl2", height = "500px")
)
)
)
server <- function(input, output){
output[["tbl1"]] <- renderDT({
datatable(dat1, escape = ncol(dat1)-1, fillContainer = TRUE)
})
output[["tbl2"]] <- renderDT({
datatable(dat2, escape = ncol(dat2)-1, fillContainer = TRUE)
})
observeEvent(input[["button"]], {
splitID <- strsplit(input[["button"]], "_")[[1]]
tbl <- splitID[2]
row <- splitID[3]
showModal(modalDialog(
title = paste0("Row ", row, " of table ", tbl, " clicked"),
size = "s",
easyClose = TRUE,
footer = NULL
))
})
}
shinyApp(ui, server)
Was able to figure it out using this.
library(shiny)
library(shinydashboard)
library(DT)
ui = dashboardPage(
dashboardHeader(),
dashboardSidebar(),
dashboardBody(
DTOutput('x1'),
verbatimTextOutput("test")
)
)
server = function(input, output) {
shinyInput <- function(FUN, len, id, ...) {
inputs <- character(len)
for (i in seq_len(len)) {
inputs[i] <- as.character(FUN(paste0(id, i), ...))
}
inputs
}
iris_rows <- nrow(iris)
iris$Timeline = shinyInput(actionButton, iris_rows, 'button_', label = "Timeline", onclick = 'Shiny.setInputValue(\"select_button\", this.id, {priority: \"event\"})' )
##DATA TABLE WHERE I NEED A BUTTON##
output$x1 = renderDT(
iris,
selection = 'single',
escape = FALSE,
options = list(
)
)
##MODAL CALLED BASED ON BUTTON CLICK
observeEvent(input$select_button, {
row <- as.numeric(strsplit(input$select_button, "_")[[1]][2])
if (is.null(row) || row == '') {} else{
showModal(modalDialog(
title = paste0("Timeline!",row),
size = "s",
easyClose = TRUE,
footer = NULL
))
}
})
output$test <- renderPrint({
as.numeric(strsplit(input$select_button, "_")[[1]][2])
})
}
shinyApp(ui, server)
Code with multiple data tables to show a separate answer than the one chosen.
library(shiny)
library(shinydashboard)
library(DT)
ui = dashboardPage(
dashboardHeader(),
dashboardSidebar(),
dashboardBody(
DTOutput('x1'),
DTOutput('x2'),
verbatimTextOutput("test")
)
)
server = function(input, output) {
shinyInput <- function(FUN, len, id, ...) {
inputs <- character(len)
for (i in seq_len(len)) {
inputs[i] <- as.character(FUN(paste0(id, i), ...))
}
inputs
}
iris2 <- iris
iris_rows <- nrow(iris)
iris$Timeline = shinyInput(actionButton, iris_rows, 'button_x1_', label = "Timeline", onclick = 'Shiny.setInputValue(\"select_button1\", this.id, {priority: \"event\"})' )
iris2_rows <- nrow(iris2)
iris2$Timeline = shinyInput(actionButton, iris2_rows, 'button_x2_', label = "Timeline", onclick = 'Shiny.setInputValue(\"select_button2\", this.id, {priority: \"event\"})' )
##DATA TABLE WHERE I NEED A BUTTON##
output$x1 = renderDT(
iris,
selection = 'single',
escape = FALSE,
options = list(
)
)
output$x2 = renderDT(
iris2,
selection = 'single',
escape = FALSE,
options = list(
)
)
##MODAL CALLED BASED ON BUTTON CLICK
observeEvent(input$select_button1, {
row <- as.numeric(strsplit(input$select_button1, "_")[[1]][3])
if (is.null(row) || row == '') {} else{
showModal(modalDialog(
title = paste0("Timeline!",row),
size = "s",
easyClose = TRUE,
footer = NULL
))
}
})
observeEvent(input$select_button2, {
row <- as.numeric(strsplit(input$select_button2, "_")[[1]][3])
if (is.null(row) || row == '') {} else{
showModal(modalDialog(
title = paste0("Timeline!",row),
size = "s",
easyClose = TRUE,
footer = NULL
))
}
})
output$test <- renderPrint({
as.numeric(strsplit(input$select_button1,"_")[[1]][3])
})
}
shinyApp(ui, server)
I tried to make a web application with R::shiny but I met a problem with a piece of code. Indeed, I would like to upload a csv file and display a correlogram.
I tried to set up the correlogram with the actionbutton() followed by the updateSelectizeInput()
However an error has been occured :
Error: Unsupported index type: NULL
Anybody have a solution ? thanks
NB - I don't want to use the fileInput widget to upload the csv file ! Only by the actionbutton !
library(shiny)
library(readr)
library(corrplot)
library(DT)
# File used for the example
data(iris)
write.csv(x = iris, file = "iris.csv")
#UI
ui <- shinyUI(
fluidPage(
navbarPage(
id = "navbar",
tabPanel(
title = "UPLOAD",
br(),
actionButton(inputId = "file", label = "ADD A FILE")
)
)
)
)
#SERVER
server <- function(input, output, session) {
path <- reactiveValues(pth = NULL)
file.choose2 <- function(...) {
pathname <- NULL;
tryCatch({
pathname <- file.choose();
}, error = function(ex) {
})
pathname;
}
observeEvent(input$file,{
path$pth <- file.choose2()
})
observeEvent(input$file, {
newvalue <- "B"
updateNavbarPage(session, "navbar", newvalue)
})
data <- reactive({
df <- readr::read_csv(file = path$pth)
return(df)
})
observeEvent(input$file, {
appendTab(
inputId = "navbar",
tabPanel(
value = "B",
title = "Corr",
sidebarLayout(
sidebarPanel(
selectizeInput(
inputId = "select04",
label = "Select features",
choices = NULL,
multiple = TRUE)
),
mainPanel(
plotOutput(
outputId = "corrplot01", height = "650px")
)
)
)
)
}, once = TRUE)
# I suppose there is a problem with this line
observeEvent(input$select04, {
col <- names(data())
col.num <- which(sapply(data(), class) == "numeric")
col <- col[col.num]
updateSelectizeInput(session = session, inputId = "select04", choices = col)
})
output$corrplot01 <- renderPlot({
df <- data()
df1 <- df[,input$select04]
corr <- cor(x = df1, use = "pairwise.complete.obs")
corrplot(corr = corr,
title = "")
})
}
shinyApp(ui, server)
I changed your ui and server a bit, but I think that might solve your problem.
I deleted the observeEvent(input$file, ...{}) from the server and added the ui part in the Ui directly.
I also added 3 req() calls in the data reactive, in the second observeEvent(input$select04, ...{}) which I changed to a normal observe and in the renderPlot call.
library(shiny)
library(readr)
library(corrplot)
library(DT)
# File used for the example
data(iris)
write.csv(x = iris, file = "iris.csv", row.names = F)
#UI
ui <- shinyUI(
fluidPage(
navbarPage(
id = "navbar",
tabPanel(
title = "UPLOAD",
br(),
actionButton(inputId = "file", label = "ADD A FILE"),
tabPanel(
value = "B",
title = "Corr",
sidebarLayout(
sidebarPanel(
selectizeInput(width = "300px",
inputId = "select04",
label = "Select features",
choices = NULL,
multiple = TRUE)
),
mainPanel(
plotOutput(
outputId = "corrplot01", height = "650px")
)
)
)
)
)
)
)
#SERVER
server <- function(input, output, session) {
path <- reactiveValues(pth = NULL)
file.choose2 <- function(...) {
pathname <- NULL;
tryCatch({
pathname <- file.choose();
}, error = function(ex) {
})
pathname;
}
observeEvent(input$file,{
path$pth <- file.choose2()
})
observeEvent(input$file, {
newvalue <- "B"
updateNavbarPage(session, "navbar", newvalue)
})
data <- reactive({
req(path$pth)
df <- readr::read_csv(file = path$pth)
return(df)
})
# I suppose there is a problem with this line
observe({
req(names(data()))
col <- names(data())
col.num <- which(sapply(data(), class) == "numeric")
col <- col[col.num]
updateSelectizeInput(session = session, inputId = "select04", choices = col)
})
output$corrplot01 <- renderPlot({
req(input$select04)
df <- data()
df1 <- df[,input$select04]
corr <- cor(x = df1, use = "pairwise.complete.obs")
corrplot(corr = corr,
title = "")
})
}
shinyApp(ui, server)
I used ShinyBS package to make a popup modal. When I hit view, it pops up a window. Inside of the popup modal is a data table made by the DT package. I wanted to select rows and display the ID number of the row I selected at the bottom of the popup window. However, I don't know what's the correct "Input" name to get it.
The following is my sample code.
#rm(list = ls())
library(DT)
library(shiny)
library(shinyBS)
library(shinyjs)
library(shinydashboard)
# This function will create the buttons for the datatable, they will be unique
shinyInput <- function(FUN, len, id, ...) {inputs <- character(len)
for (i in seq_len(len)) {
inputs[i] <- as.character(FUN(paste0(id, i), ...))}
inputs
}
ui <- dashboardPage(
dashboardHeader(title = "Simple App"),
dashboardSidebar(
sidebarMenu(id = "tabs",
menuItem("Menu Item 1", tabName = "one", icon = icon("dashboard"))
)
),
dashboardBody(
tabItems(
tabItem(tabName = "one",h2("Datatable Modal Popup"),
DT::dataTableOutput('my_table'),uiOutput("popup")
)
)
)
)
server <- function(input, output, session) {
my_data <- reactive({
testdata <- cars
as.data.frame(
cbind(
View = shinyInput(actionButton,
nrow(testdata),
'button_',
label = "View",
onclick = 'Shiny.onInputChange(\"select_button\", this.id)' ),
testdata))
})
output$my_table <- DT::renderDataTable(my_data(),selection = 'single',options = list(searching = FALSE,pageLength = 10),server = FALSE, escape = FALSE,rownames= FALSE)
SelectedRow <- eventReactive(input$select_button,{
as.numeric(strsplit(input$select_button, "_")[[1]][2])
})
observeEvent(input$select_button, {
toggleModal(session, "modalExample", "open")
})
DataRow <- eventReactive(input$select_button,{
iris
})
## I guess my input name is not right
output$y11 = renderPrint(input$popup_rows_selected)
output$popup <- renderUI({
bsModal("modalExample", paste0("Data for Row Number: ",SelectedRow()), "", size = "large",
column(12,
DT::renderDataTable(DataRow()),
h4("The following didn't show when I select the rows"),
verbatimTextOutput('y11')
)
)
})
}
shinyApp(ui, server)
This will work, the event has to be bound to the table id, which you had it for ui element(can contain multiple things)
#rm(list = ls())
library(DT)
library(shiny)
library(shinyBS)
library(shinyjs)
library(shinydashboard)
# This function will create the buttons for the datatable, they will be unique
shinyInput <- function(FUN, len, id, ...) {inputs <- character(len)
for (i in seq_len(len)) {
inputs[i] <- as.character(FUN(paste0(id, i), ...))}
inputs
}
ui <- dashboardPage(
dashboardHeader(title = "Simple App"),
dashboardSidebar(
sidebarMenu(id = "tabs",
menuItem("Menu Item 1", tabName = "one", icon = icon("dashboard"))
)
),
dashboardBody(
tabItems(
tabItem(tabName = "one",h2("Datatable Modal Popup"),
DT::dataTableOutput('my_table'),uiOutput("popup")
)
)
)
)
server <- function(input, output, session) {
my_data <- reactive({
testdata <- cars
as.data.frame(
cbind(
View = shinyInput(actionButton,
nrow(testdata),
'button_',
label = "View",
onclick = 'Shiny.onInputChange(\"select_button\", this.id)' ),
testdata))
})
output$my_table <- DT::renderDataTable(my_data(),selection = 'single',options = list(searching = FALSE,pageLength = 10),server = FALSE, escape = FALSE,rownames= FALSE)
SelectedRow <- eventReactive(input$select_button,{
as.numeric(strsplit(input$select_button, "_")[[1]][2])
})
observeEvent(input$select_button, {
toggleModal(session, "modalExample", "open")
})
DataRow <- eventReactive(input$select_button,{
iris
})
## I guess my input name is not right
output$y11 = renderPrint(input$my_test_rows_selected)
output$my_test <- DT::renderDataTable(DataRow())
output$popup <- renderUI({
bsModal("modalExample", paste0("Data for Row Number: ",SelectedRow()), "", size = "large",
column(12,
dataTableOutput("my_test"),
h4("The following didn't show when I select the rows"),
verbatimTextOutput('y11')
)
)
})
}
shinyApp(ui, server)