I am new to Shiny R.Can anyone help me solve the issue below.
I am trying to plot the data using a dataset, and with a user defined option "All" added to the "selectlist" of "region" provided in UI.
When "All" option is selected from "selectlist", how can I use the below observer to store information about all the regions into vector "l", so that the same can be used to query based on other user inputs
observe({
if("All" %in% input$region) {
selected <- setdiff(allchoice, "All")
updateSelectInput(session, "region", selected = selected)
}
})
Ref: How to add a user defined value to the select list of values from dataset
UI.R
library(shiny)
library("RMySQL")
library(ggplot2)
library(plotly)
library(DT)
library(dplyr)
dataset <- read.csv("dataset.csv", header=TRUE)
dataset$X <- NULL
allchoice <- c("All", levels(dataset$region))
fluidPage(
title = "ABC XYZ",
hr(),
fluidRow(
titlePanel("ABC XYZ"),
sidebarPanel(
dateRangeInput('dateRange',
label = 'Date Input',
start = as.Date("1967-01-01"), end = Sys.Date()),
selectInput("region", label = "Region",
choices = allchoice,
selected = 1),
selectInput("gender", label = "Gender",
choices = unique(dataset$gender), multiple = TRUE,
selected = unique(dataset$gender)),
selectInput('x', 'X', names(dataset), names(dataset)[[2]]),
selectInput('y', 'Y', names(dataset), names(dataset)[[8]]),
hr()
),
mainPanel(
column(12, plotlyOutput("plot1")),
hr(),
column(12, plotlyOutput("plot2"))
)
)
)
Server.r
library(ggplot2)
library("RMySQL")
library("mgcv")
library(plotly)
function(input, output, session) {
dataset <- read.csv("dataset.csv", header=TRUE)
dataset$X <- NULL
dataset$date <- as.Date(dataset$date)
if(input$region == "All"){
l <- observe({
if("All" %in% input$region) {
selected <- setdiff(allchoice, "All")
updateSelectInput(session, "region", selected = selected)
}
})
}
else{
l <- reactive(subset(dataset, region %in% input$region))
}
k <- reactive({subset(l(), date >= as.Date(input$dateRange[1]) & date <= as.Date(input$dateRange[2]))})
n <- reactive(subset(k(), gender %in% input$gender))
#output plots
output$plot1 <- renderPlotly({
p <- ggplot(n(), aes_string(x=input$x, y=input$y)) + geom_point(alpha=0.4)
ggplotly(p)
})
output$plot2 <- renderPlotly({
q <- ggplot(n(), aes_string(x=input$x, y=input$y)) + geom_smooth()
ggplotly(q)
})
}
Error I am facing -
Warning: 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.)
Stack trace (innermost first):
46: .getReactiveEnvironment()$currentContext
45: .subset2(x, "impl")$get
44: $.reactivevalues
43: $ [D:\Demo\server.R#36]
42: server $ [D:\Demo\server.R#36]
1: runApp
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.)
Note: My vocabulary above may be off, so please correct me if I'm wrong, I am totally new to the world of R.
Thanks in advance.
EDIT 1:
Listening on http://127.0.0.1:5128
We recommend that you use the dev version of ggplot2 with `ggplotly()`
Install it with: `devtools::install_github('hadley/ggplot2')`
Warning in origRenderFunc() :
Ignoring explicitly provided widget ID "2988253b22c1"; Shiny doesn't use them
We recommend that you use the dev version of ggplot2 with `ggplotly()`
Install it with: `devtools::install_github('hadley/ggplot2')`
`geom_smooth()` using method = 'gam'
Warning in origRenderFunc() : Ignoring explicitly provided widget ID "29885be33e8"; Shiny doesn't use them
and even when i do that, I am getting many exceptions and sometimes the same exceptions as above again. Just worried if the same will affect the application in the long run, can you suggest anything about that?
Thanks again.
You have not provided an example data so i can only guess and via looking at your error which says clearly whats the problem: no active reactive context, i assume that it is exactly in this part:
if(input$region == "All"){
l <- observe({
if("All" %in% input$region) {
selected <- setdiff(allchoice, "All")
updateSelectInput(session, "region", selected = selected)
}
})
}
else{
l <- reactive(subset(dataset, region %in% input$region))
}
[!] but actually i do not understand what for you need the observer...i think it should work totally fine if you just use if...else... statement.
[!] And additionally i have no idea why at first you say you wanna get the vector of choices (except "All") and you use it as selected choice in selectInput, may i ask what for?
and else statement should give you subset of the data based on input$region.
So shortly saying: if gives you updatedSelectInput and else gives you dataset --> It actually does not make sense at all..
and should be as simple as that, if "All" is selected then there is no need to subset the dataset, if any other choice then "All" is selected then the subset of the dataset should happen:
l <- reactive({
if(input$region == "All"){
dataset
}else{
dataset <- subset(dataset, region %in% input$region)
}})
Related
I am trying to subset my data based on inputs from renderUI. This data would then be passed to further work in an observe chunk.
Below is an example, where there is an issue with the server code. I am having difficulties with the code recognising the input to an if clause - or more accurately it starts of NULL and then "Every row" from the input is recognised. If I uncomment carbData() in observe below I get the following error. Also receive a similar error if I move the subset inside the observe environment.
Listening on http://127.0.0.1:7400
NULL ### from check()
Warning: Error in if: argument is of length zero
61: reactive:carbData [#9]
45: carbData
44: [#17]
1: runApp
Is this due to some delayed evaluation from using renderUI? If so, or otherwise how do I fix it please?
My code:
server <- function(input, output) {
amData <- reactive({ mtcars[am %in% input$am, ] })
output$gear <- renderUI({ selectInput("Gear", "GEAR",
choices=unique(amData()[, "gear"]), selected=4 ) })
gearData <- reactive({ amData()[gear %in% input$Gear, ] })
output$carb <- renderUI({ selectInput("Carb", "CARB",
choices=c("Every row", unique(gearData()[, "carb"])), selected="Every row") })
carbData <- reactive({ if(input$Carb %in% "Every row") gearData() else gearData()[ carb %in% input$Carb ] }) #### PROBLEM
# Some text where it can be seen that input$Carb is initially NULL
check <- reactive({ p <- input$Carb; print(p) })
observe({
check();
# problems with if clause in both of these:
# carbData()
# Moving the data subset inside `observe` doesn't help
# df <- if(input$Carb %in% "Every row") gearData() else gearData()[ carb %in% input$Carb ]
})
}
And the rest of the code to allow it to run:
library(shiny)
library(shinydashboard)
data(mtcars); data.table::setDT(mtcars)
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(
sidebarMenu(
selectInput("am", "AM", unique(mtcars$am), selected = "0"),
uiOutput("gear"),
uiOutput("carb")
)),
dashboardBody())
runApp(shinyApp(ui, server))
I'm a bit uncertain whether this question is closed. However, I took the luxury of editing your codes to locate the problem.
I used tibbles instead of data.table as I am not familiar with the syntax. So far #stefan is absolutely correct, req(input$Carb) will relieve you of your troubles.
The reason that gear %in% input$Gear works, and input$Carb %in% "Every row" does not, is that the reactive-hierachy does not favor input$Carb, and as it is null at startup, you are essentially testing NULL %in% "Every Row". Where as gear exists by construction at app start up.
This is not, as Im certain that you are aware of, the same as input$Carb %in% "NULL", or NULL for that matter.
This is your code that I played around with,
server <- function(input, output) {
amData <- reactive({
mtcars %>% filter(am %in% input$am)
})
gearData <- reactive({
amData() %>% filter(gear %in% input$Gear)
})
output$gear <- renderUI({
selectInput("Gear",
"GEAR",
choices = unique(amData()[, "gear"]),
selected = 4)
})
output$carb <- renderUI({
selectInput(
"Carb",
"CARB",
choices = c("Every row", unique(gearData()[, "carb"])),
selected = "Every row"
)
})
carbData <-
reactive({
req(input$Carb)
if (input$Carb %in% "Every row")
gearData()
else
gearData() %>% filter(carb %in% input$Carb)
}) #### PROBLEM
# Some text where it can be seen that input$Carb is initially NULL
check <- reactive({
p <- input$Carb
print(p)
})
observe({
check()
# problems with if clause in both of these:
carbData()
})
}
I tried to create a shinyApp with seq() function within the Apps.
header <- dashboardHeader(title = 'Testing' ,titleWidth = 300)
sidebar <- dashboardSidebar(uiOutput("sidebarpanel"), width = 300)
body <- dashboardBody(uiOutput("body"))
uix <- dashboardPage(header, sidebar, body)
serverx <- function(input, output, session){
output$sidebarpanel <- renderUI({
div(
sidebarMenu(id="tabs",
menuItem("Tes 1", tabName = "tes1", icon = icon("dashboard"), selected = TRUE)
)
)
})
output$body <- renderUI({
tabItems(tabItem(tabName = "tes1",
fluidRow(column(2, textInput("s1", "From :", value = 1))
,column(2, textInput("s2", "To", value = 7))
),
textOutput("result")
)
)
})
segment_low <- reactiveValues(ba=NULL)
segment_high <- reactiveValues(ba=NULL)
results <- reactiveValues(ba=NULL)
toListen <- reactive({
list(input$s1, input$s2)
})
observeEvent(toListen(),{
segment_low$ba <- input$s1 %>% as.numeric()
segment_high$ba <- input$s2 %>% as.numeric()
})
observe({
results$ba <- seq(segment_low$ba,segment_high$ba, 1)
})
output$result <- renderText({
results$ba
})
}
shinyApp(uix, serverx)
In that syntax, I would create a variable called results$ba because I want to escalate that value in the next time. But it turns out an error :
Warning: Error in seq.default: 'from' must be of length 1
[No stack trace available]
Could someone help me how to solve this problem? Since this error just happened if I put the reactiveValues to the seq() function, while I input a static input, for example seq(2,5,1) it will not return a error. And I already put the initial value for each input in textInput() function also.
Kindle need your help, developers!
Many Thanks.
The issue is that you're rendering the s1 and s2 inputs server-side. Because of this, the server at the beginning renders them as NULL, and your seq function errors when it gets the NULL value.
The simplest thing to do is to add a req function to prevent your code from evaluating unless it's getting some non-NULL values.
observe({
req(segment_low$ba, segment_high$ba)
results$ba <- seq(segment_low$ba,segment_high$ba, 1)
})
Basically, since you're using observe, which is very eager, you are telling the seq function to evaluate right away. By using the req function, you're stopping the chain of evaluation from happening unless the segment_low$ba and segment_high$ba have non-NULL values.
I am trying to dynamically populate the values of the selectInput from the data file uploaded by the user. The selectInput must contain only numeric columns.
Here is my code snippet for server.R
...
idx <- sapply(data.file, is.numeric)
numeric_columns <- data.file[, idx]
factor_columns <- data.file[, !idx]
updateSelectInput(session, "bar_x", "Select1", choices = names(numeric_columns))
updateSelectInput(session, "bar_y", "Select2", choices = names(factor_columns))
...
Corresponding ui.r
...
selectInput("bar_x", "Select1", choices = NULL),
selectInput("bar_y", "Select2", choices = NULL)
...
The code works fine as long as there are more than one values in any dropdown. However, it fails as soon as it encounters only one value to be displayed in the selectInput.
How can I handle this specific condition, given that the data is uploaded and it cannot be controlled if there is just one column as numeric?
It appears that in 2019, this issue still exists. The issue that I have seen is that when there is only one option in the dropdown, the name of the column is displayed instead of the one option.
This appears to only be a graphical problem, as querying the value for the selectInput element returns the correct underlying data.
I was unable to figure out why this problem exists, but an easy way around this bug is to simply change the name of the column so that it looks like the first element in the list.
library(shiny)
ui <- fluidPage(
selectInput("siExample",
label = "Example Choices",
choices = list("Loading...")),
)
server <- function(input, output, session) {
# load some choices into a single column data frame
sampleSet <- data.frame(Example = c("test value"))
# rename the set if there is only one value
if (length(sampleSet$Example) == 1) {
# This should only be done on a copy of your original data,
# you don't want to accidentally mutate your original data set
names(sampleSet) <- c(sampleSet$Example[1])
}
# populate the dropdown with the sampleSet
updateSelectInput(session,
"siExample",
choices = sampleSet)
}
shinyApp(ui = ui, server = server)
Info: Code was adapted by OP to make error reproducible.
To solve your issue use val2 <- val[,idx, drop = FALSE]
You dropped the column names by subsetting the data.frame().
To avoid this use drop = FALSE; see Keep column name when select one column from a data frame/matrix in R.
library(shiny)
# Define UI for application that draws a histogram
ui <- fluidPage(
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
# drj's changes START block 1
#selectInput('states', 'Select states', choices = c(1,2,4))
selectInput('states', 'Select states', choices = NULL)
# drj's changes END block 1
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("distPlot")
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output, session) {
observe({
#drj's changes START block 2
#val <- c(1,2,3)
#names(val) <- c("a","b","c")
#updateSelectInput(session, 'states', 'Select states', choices = names(val[1]))
val <- as.data.frame(cbind(c("_1","_2","_3"), c(4, 4, 6)))
names(val) <- c("a","b")
val$b <- as.numeric(val$b)
idx <- sapply(val, is.numeric)
val2 <- val[,idx, drop = FALSE]
updateSelectInput(session, 'states', 'Select states', choices = names(val2))
#drj's changes END block 2
})
}
# Run the application
shinyApp(ui = ui, server = server)
I've been starting to learn Shiny to try and develop some nice simple interfaces and I've managed to put together my first one below thanks to modifying some code I found at https://gist.github.com/4211337.
The code I am using is as follows:
library(shiny)
library(DT)
schedule<-read.csv("NBA_Schedule.csv")
stats<-read.csv("2015_2016_Stats.csv")
data_sets<-unique(schedule$Date)
data_sets<-as.character(data_sets)
server<-shinyServer(function(input, output) {
output$choose_dataset <- renderUI({
selectInput("dataset", "Game Date (US Time)", as.list(data_sets))
})
output$choose_columns <- renderUI({
if(is.null(input$dataset))
return()
schedule_subset<-schedule[ schedule$Date %in% input$dataset, ]
schedule_subset$Game<-as.character(schedule_subset$Game)
checkboxGroupInput("columns", "Choose Games to Include",
choices = schedule_subset$Game,
selected = schedule_subset$Game)
})
output$data_table <- DT::renderDataTable({
if(is.null(input$dataset))
return()
schedule_subset<-schedule[ schedule$Date %in% input$dataset, ]
teams_selected <- c(as.character(schedule_subset$VIS[schedule_subset$Game==input$columns]),as.character(schedule_subset$HOM[schedule_subset$Game==input$columns]))
if (is.null(input$columns))
return()
stats<-stats[ stats$Tm %in% teams_selected, ]
stats
})
})
ui<-shinyUI(pageWithSidebar(
headerPanel("2016/2017 NBA DFS (Draftstars & Moneyball) Data Summary"),
sidebarPanel(
uiOutput("choose_dataset"),
uiOutput("choose_columns"),
br(),
a(href = "https://gist.github.com/4211337", "Original source code")
),
mainPanel(
DT::dataTableOutput("data_table")
)
))
shinyApp(ui = ui, server = server)
Upon start up I get the following interface which I don't have a problem with:
Now, the functionality of the code is supposed to include teams in this table only if the players play for the teams that have their tickboxes selected. So on start up we currently have 5,463 entries which is entirely correct.
However, once I start unticking boxes, etc the table data starts returning funny numbers. If I select boxes individually then the correct numbers of rows will result in the table, ie 1767 for Knicks v Cavaliers, 1913 for Spurs v Warriors and 1783 for Jazz v Blazers. However, if I select only the bottom two matches then the table returns no results:
Or if I select the first and last match then I only get the 1767 results for Knicks v Cavaliers.
Other combinations of tickbox selections give similar incorrect results.
I would appreciate it if anybody could find the error in my code to try and resolve this issue so that I can move forward.
Does this solve the issues? I could reproduce it and now it seems to display correct results.
output$data_table <- DT::renderDataTable({
if(is.null(input$dataset))
return()
schedule_subset<-schedule[ schedule$Date %in% input$dataset, ]
teams_selected <- c(as.character(schedule_subset$VIS[schedule_subset$Game %in% input$columns]),
as.character(schedule_subset$HOM[schedule_subset$Game %in% input$columns]))
if (is.null(input$columns))
return()
stats_subset<-stats[ stats$Tm %in% teams_selected, ]
stats_subset
})
The issues seemed to have been caused by:
inaccurate subsetting criteria (correct: schedule_subset$Game %in% input$columns)
incorrect data manipulation
(correct: stats_subset<-stats[stats$Tm %in% teams_selected,]).
My problem is when selecting data using the input from "updateSelectInput".
input$State and input$Company returns no values to my "data selection" function, input$Transport that is not an "update" works fine.
How I call an input when using "updateSelectInput"? Does it work in the same way as "selectInput"?
Thanks in advance!
Here is the data I created to simplify the problem:
Company<- paste('company',1:95)
State<- paste('state',1:20)
Transport<-c('inter long','nacional long','nacional short','inter short')
variable1<- sample(0:10,380,replace=T)
variable2<- sample(0:10,380,replace=T)
variable3<- sample(0:10,380,replace=T)
variable4<- sample(0:10,380,replace=T)
mydata<- data.frame(Company,State,Transport,variable1,variable2,variable3,variable4)
ui.R
shinyUI(pageWithSidebar(
headerPanel('Passengers Data'),
sidebarPanel(
selectInput("Transport", "Select a Transport", choices = levels(mydata$Transport), selected = levels(mydata$Transport)[1]
),
selectInput("State", "Select a State", choices = sort(levels(mydata$State)),selected = sort(levels(mydata$State)[1])),
tags$hr(),
checkboxGroupInput("Company", "Select Company", choices = mydata$Company[mydata$State ==sort(mydata$State )[1] & mydata$Transport==sort(mydata$Transport)[1]]),
width = 3
),
mainPanel(
htmlOutput("plot1"),width = 9
)
))
server.R
library(ggplot2)
library(googleVis)
shinyServer(function(input, output, session) {
observe({
Transport2<- input$Transport
updateSelectInput(session, "State", choices = sort(levels(factor(mydata$State[mydata$Transport == Transport2]))),selected = sort(levels(factor(mydata$State[mydata$Transport == Transport2])))[1])
})
observe({
Transport2<- input$Transport
State2 <- input$State
updateCheckboxGroupInput(session, "Company", choices = sort(levels(factor(mydata$Company[mydata$State == State2 & mydata$Transport == Transport2]))),selected=sort(levels(factor(mydata$Company[mydata$State == State2 & mydata$Transport == Transport2])))[1:5])
})
selectedData<-reactive({
subset(mydata, mydata$Transport==input$Transport & mydata$State==input$State & mydata$Company==input$Company
)
})
output$plot1 <- renderGvis({
gvisBarChart(selectedData(), xvar="Company", yvar="variable1",
options=list(legend='none', width=750, height=425,title="Resultado geral",
titleTextStyle="{color:'black',fontName:'Courier',fontSize:16}",
bar="{groupWidth:'70%'}"))
})
})
First, there's a bug in this line:
subset(mydata, mydata$Transport==input$Transport & mydata$State==input$State & mydata$Company==input$Company
Specifically the last clause:
mydata$Company==input$Company
should be replaced with
mydata$Company %in% input$Company
since input$Company can have multiple values.
Also, the selected values you're passing to updateSelectInput are sometimes c(NA, NA, NA, NA, NA) which Shiny doesn't understand (it causes a JavaScript error in the browser). You should call na.omit on the selection before you give it to updateSelectInput. (If this makes things even worse, install the latest version of RJSONIO from CRAN--it used to have a bug with empty vectors in lists.)
Thirdly, I'd recommend adding this code to the top of your renderGvis expression:
validate(
need(nrow(selectedData()) > 0, "No data")
)
It will make it easier to detect when there are no rows in your data (rather than a blank graph which could be the result of an error or something).