I am trying to write a script in shiny, which has two inputs and stores the inputs in two different variables and runs a code using these input variables.But i am getting an error which says :Error in .getReactiveEnvironment()$currentContext() :
Operation not allowed without an active reactive context. (You tried to do something that can only be done from inside a reactive expression or observer.)
The following is my ui code:
ui <- fluidPage(
titlePanel("Network Model"),
sidebarLayout(
sidebarPanel(
selectInput(inputId = "origin",
label = "Origin:",
choices = milk_runs$Origin),
selectInput(inputId = "destination",
label = "Destination:",
choices = milk_runs$Dest),
actionButton("go", "")
),
mainPanel(
tableOutput(
"view"))
)
)
server code :
server<- function(input, output){
origin <- input$origin
destination <- input$destination
observeEvent(input$go,source("nr9.R"))
output$summary <- renderPrint({
#dataset <- datasetInput()
summary(Tnetwork)
})
Can you please tell me how to get correct results.
I think (it would help if you provided a fully reproducible example) that the error is occurring because you are trying to run input$origin without reactive(). The input$origin will not invalidate and update based on user input unless put inside reactive. Based on the example you provided:
library(shiny)
ui <- fluidPage(
titlePanel("Network Model"),
sidebarLayout(
sidebarPanel(
selectInput(inputId = "origin", label = "Origin:", choices = c("A","B","C","D","E","F")),
selectInput(inputId = "destination", label = "Destination:", choices = c("A","B","C","D","E","F")),
actionButton("go", "GO")
),
mainPanel( tableOutput( "view"))
)
)
server<- function(input, output){
origin <- reactive(input$origin)
destination<-reactive(input$destination)
observeEvent(input$go,{
cat(origin(),'nextword',destination(),sep="-")
})
output$view <- renderTable({data.frame(origin=origin(),destination=destination())})
}
shinyApp(ui, server)
should print 'origin-nextword-destination' to the console when 'go' is activated, and the table should update. I changed a few bits in your example because it was not reproducible but hopefully it helps.
Related
I have written a simple example of what I am doing. I have 3000 numbers that I want to show in a selectInput. The numbers have to be in a reactive function, since in my original work, the data is from a file.
My problem is that when I run the app it only appears 1000 numbers, not the entire data (3000 numbers).
I have seen this post Updating selection of server-side selectize input with >1000 choices fails but I don't know how can I do it using uiOutput and renderUI.
Can anyone help me?
Thanks very much in advance
The code:
library(shiny)
ui <- fluidPage(
titlePanel("Numbers"),
sidebarLayout(
sidebarPanel(
uiOutput('selectUI')
),
mainPanel(
)
)
)
server <- function(input, output) {
num <- reactive({
data = c(1:3000)
return(data)
})
output$selectUI <- renderUI({
selectInput(inputId = 'options', "Select one", choices = num())
})
}
# Run the application
shinyApp(ui = ui, server = server)
Use selectizeInput instead of selectInput with the argument options = list(maxOptions = 3000).
Thanks to Stéphane Laurent's answer, the example will be solved like this:
library(shiny)
ui <- fluidPage(
titlePanel("Numbers"),
sidebarLayout(
sidebarPanel(
selectizeInput(inputId = "options", label = "Select one", choices=character(0)),
),
mainPanel(
)
)
)
server <- function(input, output, session) {
num <- reactive({
data = c(1:3000)
return(data)
})
observe({
updateSelectizeInput(
session = session,
inputId = "options",
label = "Select one",
choices= num(), options=list(maxOptions = length(num())),
server = TRUE)
})
}
# Run the application
shinyApp(ui = ui, server = server)
This code will work if you have more than 3000 entries. It will show you ALL the choices that you have. However, if you have a long list of choices (e.g. 60000) it will decrease the speed of your app.
How can we ensure the user sees the validation error message only once?
Even in Shiny validation page, they had displayed error message twice:
https://shiny.rstudio.com/articles/validation.html
Also, if I were using different language, the below link might have helped.
Knockout - validation showing same error message twice
Even though **Stackoverflow had similar question here but referring different issue **
Show validate error message only once
It meant something different.
I am referring to "Please select a data set" message displaying twice
library(shiny)
ui <- fluidPage(
titlePanel("Validation App"),
sidebarLayout(
sidebarPanel(
selectInput("data", label = "Data set",
choices = c("", "mtcars", "faithful", "iris"))
),
# Show a plot of the generated distribution
mainPanel(
tableOutput("table"),
plotOutput("plot")
)
)
)
server <- function(input, output) {
data <- reactive({
validate(
need(input$data != "", "Please select a data set")
)
get(input$data, 'package:datasets')
})
output$plot <- renderPlot({
hist(data()[, 1], col = 'forestgreen', border = 'white')
})
output$table <- renderTable({
head(data())
})
}
shinyApp(ui,server)
If there is an error, ideally only 1 time, user should be notified if not it might be annoying.
Because you are storing the message "Please select a data set" in the reactive object data() and then calling that object to be displayed twice, once in output$plot and once in output$table.
One way to refactor the app and still have a similar experience is the use a place holder in the input widget and then req() to check if the input value is truthy. If a value is not truthy ("falsey"?) then evaluation is stopped and you won't raise errors from downstream outputs that use data().
library(shiny)
ui <- fluidPage(
titlePanel("Validation App"),
sidebarLayout(
sidebarPanel(
selectInput("data", label = "Data set",
choices = c("Please select a dataset" = "", "mtcars", "faithful", "iris"))
),
# Show a plot of the generated distribution
mainPanel(
tableOutput("table"),
plotOutput("plot")
)
)
)
server <- function(input, output) {
data <- reactive({
req(input$data)
get(input$data, 'package:datasets')
})
output$plot <- renderPlot({
hist(data()[, 1], col = 'forestgreen', border = 'white')
})
output$table <- renderTable({
head(data())
})
}
shinyApp(ui,server)
Another option would be to relocate the validate() logic from the data() block to one of the outputs. That way the message will only be shown once, but you may have to implement another check on the data, which is why I prefer using req for things like this.
I am attempting to custom build a user-interface regression tool in R shiny for practice (i.e. my own version of spss for my general use-cases). I'm having trouble with the critical step of generating a regression formula from the user-uploaded dataset. I want the user to be able to select a dependent variable from a dropdown menu (and eventually to turn those generated variables into a formula in my server code).
I have tried to use a textOutput(names(userdata())) within the choices argument for a selectInput() function so that the user can select which of their variables should be a dependent variable once they have uploaded their dataset. However, this generates a list of properties of the dataset rather than the names of the columns themselves.
I've looked into other uses of reactive datasets that others have done but no one seems to have done precisely what I am trying to do or I am searching for them badly. (It seems like the most common probable use-case for Shiny, so I can't imagine how no one has figured this out yet, but I can't find anything)
library(shiny)
library(wired)
ui <- fluidPage(
sidebarLayout(sidebarPanel(
fileInput("FileInput", "Input Your Data Set (Must be .csv)"),
wired_select(inputId = "responsevar",
label = "Dependent Varibale:",
choices = textOutput(outputId = "variable_names")
)
), #sidebar panel
mainPanel(
tabsetPanel(
tabPanel("Table",
DT::dataTableOutput("table")
)
) #tabset Panel
) #main panel
) #sidebarlayout
) #fluidpage
server <- function(input, output, session) {
datasetInput <- reactive({
infile <- input$FileInput
if (is.null(infile))
return(NULL)
read.csv(infile$datapath, header = TRUE)
})
output$table = DT::renderDataTable(datasetInput())
output$variable_names <- reactive({
if (is.null(datasetInput()))
return(NULL)
names(datasetInput())
})
} #server
shinyApp(ui = ui, server = server)
textOutput is used to output text to the Shiny UI. This is includes generating appropriate HTML. As wired_select(..., choices = ???) is expecting an R object rather than HTML code this is unlikely to work.
One approach that is likely to work is using updateSelectInput. I do not know whether this has an equivalent function with the wired library, but in base shiny I would:
Initialise the selectInput with no choices
Update the choices in the drop down once the data has been selected
Try the following:
library(shiny)
ui <- fluidPage(
sidebarLayout(sidebarPanel(
fileInput("FileInput", "Input Your Data Set (Must be .csv)"),
selectInput(inputId = "responsevar",
label = "Dependent Varibale:",
choices = NULL)
), #sidebar panel
mainPanel(
tabsetPanel(
tabPanel("Table",
DT::dataTableOutput("table")
)
) #tabset Panel
) #main panel
) #sidebarlayout
) #fluidpage
server <- function(input, output, session) {
datasetInput <- reactive({
infile <- input$FileInput
if (is.null(infile))
return(NULL)
read.csv(infile$datapath, header = TRUE)
})
output$table = DT::renderDataTable(datasetInput())
observeEvent(datasetInput(),{
updateSelectInput(session, "responsevar", choices = names(datasetInput()))
})
} #server
shinyApp(ui = ui, server = server)
Hmm... as the above does not work with the wired library, I'll suggest another possible approach. (I can't install wired in my environment, so apologies if this is no better).
The idea here is to make the selector part of a dynamic R object (a UI object). Then if a file gets loaded, the UI object, which depends on the file, will also update.
library(shiny)
library(wired)
ui <- fluidPage(
sidebarLayout(sidebarPanel(
fileInput("FileInput", "Input Your Data Set (Must be .csv)"),
uiOutput("selector")
), #sidebar panel
mainPanel(
tabsetPanel(
tabPanel("Table",
DT::dataTableOutput("table")
)
) #tabset Panel
) #main panel
) #sidebarlayout
) #fluidpage
server <- function(input, output, session) {
datasetInput <- reactive({
infile <- input$FileInput
if (is.null(infile))
return(NULL)
read.csv(infile$datapath, header = TRUE)
})
output$table = DT::renderDataTable(datasetInput())
output$selector <- renderUI({
choices <- NULL
if(!is.null(datasetInput()))
choices <- names(datasetInput())
wired_select(inputId = "responsevar",
label = "Dependent Varibale:",
choices = choices)
})
} #server
Key differences to my original answer, are uiOutput replacing selectInput and a renderUI output component instead of an observer.
In the attached MWE Shiny example, I have a nested tabsetPanel within a tabPanel for a navbar. If you run the MWE with only one tabPanel within the tabSet you will see that Shiny behaves exactly as it is expected. However, if you run the MWE with two tabPanels, the result is not printed to the main panel of each tab.
Why does this behaviour occur? And how do I resolve this conundrum?
library(shiny)
ui <- shinyUI(navbarPage("tabalicious",
tabPanel("Nav1", value = "nav1",
mainPanel(h2("Hello"),
br(),
p("This is my app.")
)
)
,
tabPanel("Nav2", value = "nav2",
tabsetPanel(
tabPanel("tabsettab1",
sidebarLayout(
sidebarPanel(
helpText("Choose your settings"),
selectInput("zone_type",
label = "Choose a zone type to display",
choices = list("Industrial", "Residential"),
selected = "Industrial")
),
mainPanel(h2("A tab for a tabSet"),
textOutput('zone_type')
)
)
)
# Uncomment this to see the issue
# ,
# tabPanel("tabsettab2",
# sidebarLayout(
# sidebarPanel(
# helpText("Choose your settings"),
# selectInput("zone_type",
# label = "Choose a zone type to display",
# choices = list("Industrial", "Residential"),
# selected = "Industrial")
# ),
# mainPanel(h2("A tab for a tabSet"),
# textOutput('zone_type')
# )
# )
# )
)
)
)
)
server <- shinyServer(function(input, output) {
output$zone_type <- renderText({
paste("You have selected", input$zone_type)
})
})
# Run the application
shinyApp(ui = ui, server = server)
It doesn't have to do with tabs, but multiple calls to output the results of the same render* function. For example, a simplified page (with no tabs) will work fine, but if you uncomment the duplicated call, will fail to display zone_type:
library(shiny)
server <- shinyServer(function(input, output) {
output$zone_type <- renderText({paste("You have selected", input$zone_type)})
})
ui <- shinyUI(fluidPage(
selectInput("zone_type",
label = "Choose a zone type to display",
choices = list("Industrial", "Residential")),
# textOutput('zone_type'),
textOutput('zone_type')
))
runApp(shinyApp(server = server, ui = ui))
While your shinyUI function can only call each output of shinyServer once, within shinyServer you can call the inputs as many times as you like, so it's easy to duplicate outputs:
library(shiny)
server <- shinyServer(function(input, output) {
output$zone_type <- renderText({paste("You have selected", input$zone_type)})
output$zone_type2 <- renderText({paste("You have selected", input$zone_type)})
})
ui <- shinyUI(fluidPage(
selectInput("zone_type",
label = "Choose a zone type to display",
choices = list("Industrial", "Residential")),
textOutput('zone_type'),
textOutput('zone_type2')
))
runApp(shinyApp(server = server, ui = ui))
If you don't want to duplicate work for the server, you can't pass one output to another, but you can just save the render* results to a local variable which you can pass to both outputs:
server <- shinyServer(function(input, output) {
zone <- renderText({paste("You have selected", input$zone_type)})
output$zone_type <- zone
output$zone_type2 <- zone
})
I am new to shiny (and any web app stuff), but fairly well versed in R. I am trying to build a fairly basic page, which runs an API call before loading the page, takes some input based on the response, and then runs another API call and does some analysis. I am having trouble with the inputs.
Here is my UI:
shinyUI(fluidPage(
# Application title
titlePanel("IGP Risk Analysis"),
sidebarLayout(
sidebarPanel(
selectInput("portfolio", "Underlying Portfolio:",
choices = portfolioList),
selectInput("portDate", "Portfolio Date:",
choices = "Pick a portfolio..."),
width = 2),
mainPanel(
tabsetPanel(type = "tabs",
tabPanel("Plot", plotOutput("plot")),
tabPanel("Summary", verbatimTextOutput("summary")),
tabPanel("Table", tableOutput("table"))
)
)
)
))
My server code is below:
shinyServer(function(input, output, session) {
portfolioInput <- reactive({
temp <- setnames(sendRequest(theURL, myUN, myPW, action = "GetPortfolios"), "Available Portfolios")
portfolioList <- temp[!grepl("AAA|ZZZ",unlist(temp)),]
return(portfolioList)
})
observe({
portfolioDates <- setnames(sendRequest(theURL, myUN, myPW, action = "GetPortfolioDates",
portfolioName = input$portfolio, portfolioCurrency = "USD"),
"Available Dates")
updateSelectInput(session, "portDate",
choices = c("Pick One", portfolioDates),
selected = "Pick One")
})
})
It is working, without errors or warnings, but the first input box is displaying the results of sendRequest(). It is not setting the names, or subsetting the response. I.e. - in the first selectInput box I am getting:
theResponse.ArrayOfString.string
AAA - IGP\\Diver\\20151007
AAA - IGP\\Diver\\TEST
REAL
BD
Bvdh
Cap
Cas
Diver
IGP Aggregate
ZZZ - Archive
ZZZ - Archive\\AAA - IGP
Where I want:
Available Portfolios
REAL
BD
Bvdh
Cap
Cas
Diver
IGP Aggregate
This makes no sense to me, as it seems to be ignoring code.
Since the portfolioList is static, in that is only needs to be loaded once when you first load the page, I tried getting the list outside of the server function. I was thinking this would set a global variable I could then reference in the UI. This did not work. Any thoughts why that approach wouldnt work?
Does this have anything to do with the 'session' in the server function? Do I have old sessions running or something? Is 'session' the R session? Does it restart when I restart the app in RStudio?
To give you something to start with, minimal example of renderUI:
shinyApp(
ui = sidebarLayout(
sidebarPanel(
uiOutput("portfolio"),
selectInput("portDate", "Portfolio Date:",
choices = "Pick a portfolio..."),
width = 2),
mainPanel()),
server = function(input, output) {
ui1 <- reactive({
temp <- c("AAA","1","2","3","ZZZ")
temp[!grepl("AAA|ZZZ",temp)]
})
output$portfolio <- renderUI ({
selectInput("portfolio", "Underlying Portfolio:",
choices = ui1())
})
}
)
To add on my comments, you can't simply call functions or objects in ui.r, you render your objects in server.r and call those objects, marked as output$name in ui.r.
I would advise you to do the shiny tutorials http://shiny.rstudio.com/tutorial/.
Thanks everybody!!! I figured it out, or I figured out a solution to the problem. Much thanks to Sebastion for steering me in the right direction. (Also thanks to this post.) I only posted an answer to kind of put a bow on this. All props to Sebastion and others.
Here is the working ui:
shinyUI(fluidPage(
# Application title
titlePanel("IGP Risk Analysis"),
sidebarLayout(
sidebarPanel(
uiOutput("portfolio"),
uiOutput("portDate"),
width = 2),
mainPanel(
tabsetPanel(type = "tabs",
tabPanel("Plot", plotOutput("plot")),
tabPanel("Summary", verbatimTextOutput("summary")),
tabPanel("Table", tableOutput("table"))
)
)
)
))
Here is the server:
shinyServer(function(input, output, session) {
output$portfolio <- renderUI ({
temp <- setNames(sendRequest(theURL, myUN, myPW, action = "GetPortfolios"), "Available Portfolios")
temp <- temp[sapply(temp, function (x) !grepl("AAA|ZZZ",x)),]
selectInput("portfolio", "Underlying Portfolio:", choices = c("Pick One",temp))
})
output$portDate <- renderUI ({
if (is.null(input$portfolio) || input$portfolio == "Pick One") return() else {
portfolioDates <- setNames(sendRequest(theURL, myUN, myPW, action = "GetPortfolioDates",
portfolioName = input$portfolio, portfolioCurrency = "USD"),
"Available Dates")
selectInput("portDate", "Portfolio Date",
choices = c("Pick One", portfolioDates),
selected = "Pick One")
}
})
})