So I have what in my head is a simple problem.
I have a selectInput. Let's call it report_select with the options "Report 1" and "Report 2" to choose from.
In addition, I have a textInput (which is used to specify an employee ID)
I have two reactives (lets call them r_one and r_two). These result in separate data based on the employee.
I have an output$table1
The goal: I want the dropdown to control WHICH of the two reactive reports to display in table1.
Note 1: The tables individually work fine. I can display one after the other without issue.
Note 2: I am using SHINY as well as tabsetpanel and tabpanel for organization
Any methodology to help with this?
METHOD 1: (Error is "Reading Objects from shionyoutput object not allowed)
library(shiny)
library(readxl)
library(dplyr)
library(tidyr)
# Globally Pull In Files
new_compdump_data <- read_xlsx("C:/temp/FILE.xlsx")
#Format Imported Data
clean_new <- subset(new_compdump_data,is.na(new_compdump_data$Term_Date))
clean_new$AIN <- as.numeric(clean_new$AIN)
clean_new$`MIP value` <- clean_new$`MIP%`*clean_new$Salary
# Begin UI
ui <- fluidPage(
titlePanel("Data Tool"),
sidebarLayout(
sidebarPanel(
selectInput(inputId = "report_select",
label = "Select a Report",
choices = c("Base Info","Stock Info")),
textInput("stock_ain","AIN")
), #End SideBarPanel
mainPanel(
tabsetPanel(
tabPanel(title="Base Info",tableOutput("table1")
)))
))
#======= SHINY - Server Section
server <- function(input, output) {
report1 <- reactive({
subset(clean_new[c(5,1,2,3)],clean_new$AIN==input$AIN)
})
report2 <- reactive({
subset(clean_new[c(5,6,7,8)],clean_new$AIN==input$AIN)
})
report_choose <- reactive({
ifelse(input$report_select=="Base Info",report1(),
ifelse(input$report_select=="Stock Info",report2()))
})
output$table1({
report_choose()
})
} #End server info
# Run the App
shinyApp(ui = ui, server = server)
METHOD 2: Error: Same as Above
Same as above but reactive for report_choose is:
report_choose <- reactive{(
switch(input$report_select,
"Base Info"=report1(),
"Stock Info"=report2())
)}
METHOD 3: (Error is "Reading Objects from shionyoutput object not allowed)
Same (section) as above but
report_choose <- reactive({
if(input$report_select=="Base Info") {
report1()
} else {
report2()
}
})
Still no dice. Any ideas or methodology?
Related
I try to create a shiny app in which one can choose from different dfs. Then one can edit values in the table. At last I would like to download the edited table.
Each step for itself , edit and download, select and download is no problem. All three together: great despair.
I don't seem to understand how Shiny updates the reactive values and how you can cut it off with isolate.
library(shiny)
library(DT)
ui <- fluidPage(
# App title ----
titlePanel("Downloading Data"),
# Sidebar layout with input and output definitions ----
sidebarLayout(
# Sidebar panel for inputs ----
sidebarPanel(
# Input: Choose dataset ----
selectInput("dataset", "Choose a dataset:",
choices = c("rock", "pressure", "cars"), multiple=T),
actionButton(inputId = "goButton",
label = "Run Report"),
# downloadbutton
downloadButton("downloadData", "Download")
),
# Main panel for displaying outputs ----
mainPanel(
DTOutput("x1")
)
)
)
#df <- cars #if this is taken instead of the first "eventReactive" it works
server <- function(input, output) {
eventReactive({
# Take a dependency on input$goButton
input$goButton
# Use isolate() to avoid dependency on input$obs
df <- isolate(input$dataset)
})
#render the editable DT
output[["x1"]] <- renderDT({
datatable(
df,
selection = "single",
editable = TRUE
)
})
# Creating a DF with the edited info
aniRoi2 <- reactiveVal(df)
#Creating proxy
proxy <- dataTableProxy("x1")
#storing edited df in proxy
observeEvent(input[["x1_cell_edit"]], {
info <- input[["x1_cell_edit"]]
newAniroi2 <-
editData(aniRoi2(), info, proxy, rownames = TRUE, resetPaging = FALSE)
aniRoi2(newAniroi2)
saveRDS(newAniroi2, "data_entry_form.rds") # save rds
})
#download the proxy
output$downloadData <- downloadHandler(
filename = function() {
paste("data-", Sys.Date(), ".csv", sep="")
},
content = function(file) {
write.csv(aniRoi2(), file)
}
)
}
shinyApp(ui, server)
Here I try to select a dataset, that only gets loaded by press of a button. Then it should behave like a normal data.frame or tibble.
If I take out the possibilty of selection of dataframes and call between "ui" and "server" "df <- cars" then it works as intended.
As of now I get the error message:
Listening on http://127.0.0.1:4060
Warnung: Error in is_quosure: Argument "expr" fehlt (ohne Standardwert)
52: is_quosure
51: exprToQuo
50: eventReactive
49: server [#2]
3: runApp
2: print.shiny.appobj
1:
Error in is_quosure(expr) : Argument "expr" fehlt (ohne Standardwert)
Thank you very much, any help would be much appreciated. It feels as if I am so close (but it feels like that since a week).
I also tried this download edited data table gives warning in shiny app it uses observe to wrap the selection. But in the shiny-app I get the familiar "Error 'data' must be 2-dimensional (e.g. data frame or matrix)"
PS: If you would forgive a bonus question: How do you debug shiny? I mean how can you see inside of what is happening, how the environment looks like and which processes are working?
There are some issues with your code. First, input$dataset is a character string with the name of the chosen dataset, not the dataset itself. To get the dataset use e.g. get(input$dataset). Second, the way you use eventReactive is interesting. (; Overall I would go for an observeEvent to init your reactiveVal aniRoi2 with the chosen dataset. Finally I have set multiple=FALSE in your selectInput as choosing multiple df's breaks your code and allowing the user to select multiple dfs makes no sense to me. (I guess that you have done this to get rid of the pre-selected value?? )
library(shiny)
library(DT)
ui <- fluidPage(
titlePanel("Downloading Data"),
sidebarLayout(
sidebarPanel(
selectInput("dataset", "Choose a dataset:",
choices = c("rock", "pressure", "cars"), multiple = FALSE
),
actionButton(
inputId = "goButton",
label = "Run Report"
),
downloadButton("downloadData", "Download")
),
mainPanel(
DTOutput("x1")
)
)
)
server <- function(input, output) {
aniRoi2 <- reactiveVal()
observeEvent(input$goButton, {
aniRoi2(get(input$dataset))
})
output[["x1"]] <- renderDT({
datatable(
aniRoi2(),
selection = "single",
editable = TRUE
)
})
proxy <- dataTableProxy("x1")
observeEvent(input[["x1_cell_edit"]], {
info <- input[["x1_cell_edit"]]
newAniroi2 <-
editData(aniRoi2(), info, proxy, rownames = TRUE, resetPaging = FALSE)
aniRoi2(newAniroi2)
})
output$downloadData <- downloadHandler(
filename = function() {
paste("data-", Sys.Date(), ".csv", sep = "")
},
content = function(file) {
write.csv(aniRoi2(), file)
}
)
}
shinyApp(ui, server)
I'm building an application in which we have 2 fluidPage(). First fluidPage() have a data table with a hyperlink in one column, which gets linked with other fluidPage().
While looking for this scenario, I came upon this solution which links to another tabPanel().
I tried to create two fluidPage() like this
library(shiny)
library(DT)
server <- function(input, output) {
output$iris_type <- DT::renderDataTable({
datatable(data.frame(Species=paste0("<a href='#filtered_data'",
"alt='",unique(iris$Species),"'",
"onclick=\"",
"$('#filtered_data').trigger('change').trigger('shown');",
"Shiny.onInputChange('species', getAttribute('alt'));",
"\">",
unique(iris$Species),
"</a>")),
escape = FALSE)
})
output$filtered_data <- DT::renderDataTable({
if(is.null(input$species)){
datatable(iris)
}else{
datatable(iris[iris$Species %in% input$species, ])
}
})
}
ui <- shinyUI(fluidPage(
mainPanel(
tabsetPanel(
tabPanel("Iris Type", DT::dataTableOutput("iris_type"))
))
),
fluidPage(
mainPanel(
DT::dataTableOutput("filtered_data")
)
)
)
shinyApp(ui = ui, server = server)
I'm getting an error message
Error in shinyUI(fluidPage(mainPanel(tabsetPanel(tabPanel("Iris Type", :
unused argument (fluidPage(mainPanel(DT::dataTableOutput("filtered_data"))))
Can anyone provide a suitable solution where on clicking the specific species, the corresponding table should get displayed on another page rather than being displayed in another tab?
Thanks in advance!!!
super new to shiny, have a problem that seems like it should be basic reactive programming but I haven't been able to find a solution that's worked so far.
Essentially, I want to take the user's selected input from the UI and paste it into a simple object in the server that will react/update when a new input is chosen.
The object will be concatenated into a full API call, and I wish to rerun the API call in the server with the reactive object updated each time a new input is chosen for it (note: the API cannot be run without an access code which is part of a corporate account, so apologies for my hesitance to put my full code but I just need help with this one functionality.)
In code below:
with Dollar General as the default selection in the selectInput, I would like the object, query, to be the character string "dollar%20general", and reactively change to "walmart" should Walmart be selected
Thanks!
ui <- fluidPage
sidebarLayout(
sidebarPanel(
selectInput("company", "Choose company:",
c("Dollar General" = "dollar%20general",
"Dollar Tree" = "dollar%20tree",
"Walmart" = "walmart"))
...
server <- function(input,output) {
...
query <- paste(input$company)
...
you can use reactiveValues() and observe. This should work:
library(shiny)
# Define UI for application
ui <- fluidPage(
# your input
sidebarLayout(
sidebarPanel(
selectInput("company", "Choose company:",
c("Dollar General" = "dollar%20general",
"Dollar Tree" = "dollar%20tree",
"Walmart" = "walmart"))
),
# Determine Output
mainPanel(
textOutput("showInput") # you need to render this in your server file
)
)
)
server <- function(input, output) {
# Show what was selected
query <- reactiveValues()
observe(
query$test <- paste(input$company, "and test", sep = " ")
)
output$showInput <- renderText({ #based on what you defined in the ui
query$test
})
}
# Run the application
shinyApp(ui = ui, server = server)
Create two files named ui.R and server.R store the UI logic in ui.R and backend/object logic in server.R. Below is the implementation.
UI file
# UI of app
ui <- fluidPage(
# input
sidebarLayout(
sidebarPanel(
selectInput("company", "Choose company:",
c("Dollar General" = "dollar%20general",
"Dollar Tree" = "dollar%20tree",
"Walmart" = "walmart"))
),
# Output
mainPanel(
textOutput("Input")
)
)
)
Server/Backend File
server <- function(input, output) {
# Show what was selected
output$Input <- renderText({ #based on what you defined in the ui
input$company
})
}
Now store these in a directory and then call runApp function.
~/newdir
|-- ui.R
|-- server.R
runApp("newdir")
I try to make a shiny module to present data from dataframes using the DT package. I would like to use a module to have a standard set up of DT-table options like language and others.
I want the user to be able to select different subsets of the data interactively and thereafter be able to see the data as a DT-table. The selection of the subset will be generated outside the module because I would like the subset to be available for other uses, for example to be exported to a csv-file.
This works as intended when I don't use a module for making the DT table. When I put the code inside a module, a table is produced when the app starts. But when the selection criteria are changed, the table don't update.
I have included an app illustrating the problem. Table 1 is generated without using shiny module and updates as expected when the selection changes. Table 2 is output using the module and don't update when the selection is changed.
I'm running R-studio 1.1.463, R version 3.5.2 and DT version 0.5.
require("DT")
require("shiny")
# module for presenting data using DT
showDTdataUI <- function(id) {
ns <- NS(id)
tagList(
DT::dataTableOutput(ns("table"))
)
}
showDTdata <- function(input, output, session, DTdata) {
output$table <- renderDataTable({
DT::datatable(DTdata)
})
}
# User interface
ui <-
fluidPage(
sidebarLayout(
sidebarPanel(id="DT",
width = 4,
helpText(h4("Select")),
selectInput("selectedSpecies", label = "Species",
choices = c("setosa","versicolor","virginica"),
selected = "versicolor")
),
mainPanel(
h3("Table 1. Presenting selected data from Iris" ),
DT::dataTableOutput("table"),
h5(br("")),
h3("Table 2. Presenting selected data from Iris using shiny module"),
showDTdataUI(id="testDTModule")
)
)
)
# Define server logic ----
server <- function(session, input, output) {
selectedIris <- reactive ( {
selected <- iris[which(iris$Species==input$selectedSpecies),]
selected
})
output$table <- renderDataTable({
DT::datatable(selectedIris())
})
callModule(showDTdata, id="testDTModule", DTdata=selectedIris())
}
# Run the app ----
shinyApp(ui = ui, server = server)
You have to pass the reactive conductor in showDTdata:
showDTdata <- function(input, output, session, DTdata) {
output$table <- renderDataTable({
DT::datatable(DTdata()) # not datatable(DTdata)
})
}
callModule(showDTdata, id="testDTModule", DTdata=selectedIris) # not DTdata=selectedIris()
Does this do what you want? I removed your functions and added the selection ='multiple' to table 1 (tableX) so that we can then listen to tableX_rows_selected
P.S.: I have noticed that if you first load DT and then shiny, that the whole app won't work anymore. This is a bit weird since we call all datatable functions with DT::... but, you do get a warning message that some parts of DT are masked by shiny or viceversa.
require("shiny")
require('DT')
# User interface
ui <-
fluidPage(
sidebarLayout(
sidebarPanel(id="DT",
width = 4,
helpText(h4("Select")),
selectInput("selectedSpecies", label = "Species",
choices = c("setosa","versicolor","virginica"),
selected = "versicolor")
),
mainPanel(
h3("Table 1. Presenting selected data from Iris" ),
DT::dataTableOutput("tablex"),
br(),
h3("Table 2. Presenting selected data from Iris using shiny module"),
DT::dataTableOutput("table2")
)
)
)
# Define server logic ----
server <- function(session, input, output) {
values <- reactiveValues(rowselect = numeric())
selectedIris <- reactive ( {
selected <- iris[which(iris$Species==input$selectedSpecies),]
selected
})
output$tablex <- renderDataTable({
DT::datatable(selectedIris(), selection = 'multiple')
})
IrisSelected <- reactive({
df <- iris[c(input$tablex_rows_selected), ]
df
})
output$table2 <- renderDataTable({
req(nrow(IrisSelected()) > 0)
DT::datatable( IrisSelected())
})
}
# Run the app ----
shinyApp(ui = ui, server = server)
Without knowing of the shiny module approach, I would have probably written it like a normal function. The app below works but I am curious now after seeing the answer by #Stephane what the advantages are of using callModule approach over regular function approach
require("DT")
require("shiny")
makeTable <- function(dataframe) { DT::datatable(dataframe) %>%
formatStyle(names(dataframe), background = '#fff')
}
# User interface
ui <-
fluidPage(
sidebarLayout(
sidebarPanel(id="DT",
width = 4,
helpText(h4("Select")),
selectInput("selectedSpecies", label = "Species",
choices = c("setosa","versicolor","virginica"),
selected = "versicolor")
),
mainPanel(
dataTableOutput('Table1')
)
)
)
# Define server logic ----
server <- function(session, input, output) {
selectedIris <- reactive ( {
selected <- iris[which(iris$Species==input$selectedSpecies),]
selected
})
output$Table1 <- renderDataTable(makeTable(selectedIris()))
}
# Run the app ----
shinyApp(ui = ui, server = server)
I have an application which has 3 tabItems. I want to use a slider on second page to display same result on 3rd page interactively, i.e. if 2nd page slider changes then 3rd page slider should also change respectively.
I have a reactive function on server side
choose_segment <- reactive({
Multiple conditions for dropdown{Due to security cant share the exact code.}
})
and this choose_segment is refered in UI once and now i want to use it on the third page as well, but when i am calling the function on third page it is not displaying any thing on ui and also not giving any error.
in UI it is called inside UIoutput.
uiOutput(choose_segment())
My observations : I think as per my study we can not call one function directly twice, so what i am doing is i have made two different functions and calling same function from them, i.e.
output$chooseSegment1 <- renderUI({
choose_segment()
})
output$chooseSegment2 <- renderUI({
choose_segment()
})
Issue : it is giving me output but they both are not interactive :(
Kindly provide a solution so that i can make both the sliders work in interactive manner.
I have faced the same scenario, in that i was suppose to change the code structure.
I made dynamic output uiOutput to the Dropdown menu ob ui and then used the same in my server as Input$xyz in observe on server and it worked for me.
Code :
UI : column(3, selectInput(inputId="ABC",label= "Choose ABC"))
column(3, selectInput(inputId="ABC1",label= "Choose ABC"))
Server : observe({
if(is.null(tab2_summary())) return(NULL)
updateSelectInput(session, "ABC", value = input$ABC)
})
observe({
updateSelectInput(session, "ABC1", value = input$ABC)
})
observe({
updateSelectInput(session, "ABC", value = input$ABC1)
})
So this is how i was able to make the selectInput interactive on two different page.
For your reference there is one full reproducible code.
Kindly refer,
library(shiny)
# UI ----------------------------------------------------------
ui <- navbarPage("Navbar!",
tabPanel("Plot", sidebarLayout(sidebarPanel(
radioButtons("yaxis1", "y-axis", c("speed"="speed", "dist"="dist"),
selected = "speed"
)),
mainPanel( plotOutput("plot"),
textOutput("test2")))), # for input checking
tabPanel("Summary", sidebarLayout(sidebarPanel(
radioButtons("yaxis2", "grouping-var", c("speed"="speed", "dist"="dist")
)),
mainPanel(
verbatimTextOutput("summary"),
textOutput("test1")
)))
)
# Server ------------------------------------------
server <- function(input, output, session) {
observe({
x <- input$yaxis1
updateRadioButtons(session, "yaxis2", selected = x)
})
observe({
y <- input$yaxis2
updateRadioButtons(session, "yaxis1", selected = y)
})
# output$test1 <- renderPrint({cat("yaxis1", input$yaxis1)})
# output$test2 <- renderPrint({cat("yaxis2", input$yaxis2)})
# output$plot <- renderPlot({ plot(cars[['speed']], cars[[input$yaxis1]]) })
# output$summary <- renderPrint({ summary(cars[[input$yaxis2]]) })
}
shinyApp(ui, server)
I Hope it will of your help.