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).
Related
In this minimal example I want to have an option to select choices more than once i.e. to produce input value as e.g. A,B,B,B,A,A,C
Option hideSelected = FALSE makes selected options still visible, but not selectable again.
According to https://github.com/rstudio/shiny/issues/518 there is such an option in selectize but I can't find such an option even here: https://github.com/selectize/selectize.js/blob/master/docs/usage.md
server <- function(input, output, session) {
output$multipleSelect <- renderUI({
selectizeInput("selectMany",
label = "I want to select each multiple times",
choices = LETTERS[1:3],
multiple = TRUE,
options = list(hideSelected = FALSE))
})
}
ui <- function() {
fluidPage(
uiOutput("multipleSelect")
)
}
shinyApp(ui, server)
Since Shiny hasn't implemented this yet and if you'd like to stick to selectInput, a workaround would be using a selectInput but clears the selection everytime the user makes a choice. Then you can put another DT output to show the currently selected elements and let the user delete elements from there. I'm using verbertimTextOutput just for demo purpose.
library(shiny)
ui <- fluidPage(
selectInput(
"selectMany",
label = "Many",
choices = LETTERS[1:3],
multiple = TRUE
),
verbatimTextOutput("debug")
)
server <- function(input, output, session) {
elements <- reactiveVal(c())
observeEvent(input$selectMany, {
req(input$selectMany)
elements(c(elements(), input$selectMany[[1]]))
})
observeEvent(elements(), {
req(elements())
updateSelectInput(session, "selectMany",
selected = character(0),
choices = LETTERS[1:3]
)
})
output$debug <- renderPrint({
print(elements())
})
}
shinyApp(ui, server)
I've come up with some good idea of adding invisible space to choices list. I've also trick selectize by adding " " option at the beggining, which solves problem of lack of reactivity when removing last element.
Here is sth that pretty much does the job - excellent when adding items.
There are still two unresolvable problems:
dropdown list is closed each time (won't be fixable as input needs to be updated)
when removing item there is blink of too many options on dropdown list
code:
library(shiny)
library(dplyr)
server <- function(input, output, session) {
# set the default choices and set previous selection to initial selectInput vector
globalList <- reactiveValues(ManyChoices = LETTERS[1:3], SelectedPrev = c())
output$multipleSelect <- renderUI({
selectizeInput("selectMany",
label = "I want to select each multiple times",
choices = c(" ", globalList$ManyChoices),
selected = " ",
multiple = TRUE,
options = list(closeAfterSelect = TRUE, openOnFocus = TRUE))
})
observeEvent(input$selectMany, {
# if sth was added
if(length(input$selectMany) > length(globalList$SelectedPrev)) {
#find out what was modified
vDiff <- setdiff(input$selectMany, globalList$SelectedPrev) %>% setdiff(., " ")
# used when removing " " and selecting sth to double the selection
if(length(vDiff) == 0) vDiff <- input$selectMany[length(input$selectMany)]
req(input$selectMany != " ") # if only " " is selected then there is no need to update
# get the position of selected element
vIndex <- which(globalList$ManyChoices == vDiff)
vLength <- length(globalList$ManyChoices)
# create new choices in the correct order
globalList$ManyChoices <- c(globalList$ManyChoices[1:vIndex],
paste0(vDiff, " "),
if(vIndex < vLength) {globalList$ManyChoices[(vIndex + 1):vLength]})
} else {
# remove the version with additional space when value was removed
vDiff <- setdiff(globalList$SelectedPrev, input$selectMany)
globalList$ManyChoices <- setdiff(globalList$ManyChoices, paste0(vDiff, " "))
}
# update previous selection
globalList$SelectedPrev <- input$selectMany
# update input with same selection but modified choices
updateSelectizeInput(session = session,
inputId = "selectMany",
selected = c(" ", input$selectMany),
choices = c(" ", globalList$ManyChoices))
})
}
ui <- function() {
fluidPage(
uiOutput("multipleSelect")
)
}
shinyApp(ui, server)
biz1 = data.frame(
Stock = query11$MONTHNAME,
SaleDate=query11$SALE_DATE,
Total = as.numeric(as.character(query11$TOTAL)),
NumberOfBills=query11$TRIID,
year=query11$YEAR,
stringsAsFactors = FALSE
)
output$Box3 = renderUI(
if (USER$Logged==TRUE){
selectInput("yr","select a year",c(unique(biz1$year),"pick one"),"pick one")
})
output$Box4= renderUI(
if (USER$Logged==TRUE)
{
if (is.null(input$yr) || input$yr == "pick one"){return()
}else selectInput("sector",
"Select a Month",
c(unique(biz1$Stock[which(biz1$year%in%input$yr)]),"pick one"),
"pick one")
})
here is the subdata2 is the reactive function where i want to distinguish data on the basis of both input but i am not to pass in correct format
subdata2 = reactive(biz1[which(biz1$Stock%in%input$sector),]&&biz1[which(biz1$Stock%in%input$yr)])
Since there was not enough information and no reproducible example, I have tried to solve the question assuming that there was no error generated in Shiny and that the problem was subsetting the data.
Your code to subset the data
subdata2 = reactive(biz1[which(biz1$Stock%in%input$sector),]&&biz1[which(biz1$Stock%in%input$yr)])
There are 3 mistakes that I see:
which(biz1$Stock%in%input$yr), here you are subsetting the Stock column using the input$yr value
The use of && vs &, here the longer form evaluates left to right examining only the first element of each vector. Check ?"&&"to learn more
The use of which, in your code you are subsetting the same data frame separately and then comparing them with &&, instead you should, for eg. biz1[which(biz1$Stock %in% input$sector & biz1$year %in% input$yr),]
Full Solution
library(shiny)
biz1 = data.frame(Stock = 1:12, year = 2016:2017, test = c("a", "b", "c"),
stringsAsFactors = FALSE)
ui <- fluidPage(
uiOutput("Box3"),
uiOutput("Box4"),
dataTableOutput("tbl")
)
server <- function(input, output, session){
output$Box3 = renderUI({
selectInput("yr","select a year",c(unique(biz1$year),"pick one"),"pick one")
})
output$Box4= renderUI({
if (is.null(input$yr) || input$yr == "pick one") {
return()
} else selectInput("sector",
"Select a Month",
c(unique(biz1$Stock[which(biz1$year%in%input$yr)]),"pick one"),
"pick one")
})
# Note the usage of 'which' and '&' to subset the data frame
output$tbl <- renderDataTable({
biz1[which((biz1$Stock%in%input$sector) & (biz1$year%in%as.numeric(input$yr))), ]
})
}
shinyApp(ui, server)
You can use filter fn
subdata2 = reactive({
x <- filter(biz1,Stock%in%input$sector, year%in%input$yr)
x
})
I am new to RShiny. I want to populate RShiny dropdowns based previous selections.
For E.g. in the image below,
User first selects the 'route', upon which 'schedule' drop-down gets populated, then user selects 'schedule', then 'trip' drop-down is populated and user selects a 'trip' input.
This is my code:
library(shiny)
library("plotly")
library(lubridate)
require(rgl)
require(akima)
library(dplyr)
library(DT)
data335 <<- read.csv("final335eonly.csv")
#data335[c(2,4,5,8,9,10)] = lapply(data335[c(2,4,5,8,9,10)], as.numeric)
routes <<- as.vector(unique(data335[,'route_no']))
ui <- fluidPage(
titlePanel("Demand Analysis"),
selectInput("routeInput", "Select the route", choices = routes),
selectInput("scheduleInput", "Select the schedule", c("")),
selectInput("tripInput", "Select the trip", c(""))
)
server <- function(input, output, session) {
observeEvent(input$routeInput,
{
x <<- input$routeInput
updateSelectInput(session, "scheduleInput",
choices = data335[data335$route_no == input$routeInput, ]$schedule_no,selected = tail(x, 1)
)
}
)
observeEvent(input$scheduleInput,
{
y <<- input$scheduleInput
updateSelectInput(session, "tripInput",
choices = data335[(data335$route_no == input$routeInput & data335$schedule_no == input$scheduleInput), ]$trip_no,selected = tail(y, 1)
)
}
)
}
shinyApp(ui = ui, server = server)
The input csv file required is here:
Whenever I try to run this seemingly simple code, eventhough the UI appears, when I try to select the inputs in dropdown, RShiny crashes.
Can you please let me know what is causing this?
The problem is happening because you are not giving unique values as choices. data335[data335$route_no == input$routeInput, ]$schedule_no have duplicate values which causes the crash.
Also, you are selecting the value of input$routeInput in your scheduleInput, which is not listed in the choice could be another reason for the crash.
Just commenting the two statements and adding unique to your choices resolves the crash.
Also as #parth pointed out in his comments why are you using <<- everywhere in your code, it not necessary. Although its not the cause of the crash, until and unless you want to share variables between sessions use of <<- inside the server is not a good practice.
Here is your code with the commented section with two selected arguments commented and unique added that works:
library(shiny)
library("plotly")
library(lubridate)
require(rgl)
require(akima)
library(dplyr)
library(DT)
data335 <<- read.csv("final335eonly.csv", stringsAsFactors = FALSE)
routes <<- as.vector(unique(data335[,'route_no']))
ui <- fluidPage(
titlePanel("Demand Analysis"),
selectInput("routeInput", "Select the route", choices = routes),
selectInput("scheduleInput", "Select the schedule", c("")),
selectInput("tripInput", "Select the trip", c(""))
)
server <- function(input, output, session) {
observeEvent(input$routeInput,
{
x <<- input$routeInput
updateSelectInput(session, "scheduleInput",
choices =unique(data335[data335$route_no == input$routeInput, ]$schedule_no),#selected = tail(x, 1)
)
}
)
observeEvent(input$scheduleInput,
{
y <<- input$scheduleInput
updateSelectInput(session, "tripInput",
choices = unique(data335[(data335$route_no == input$routeInput & data335$schedule_no == input$scheduleInput), ]$trip_no),#selected = tail(y, 1)
)
}
)
}
shinyApp(ui = ui, server = server)
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)
}})
I asked this question (Update two sets of radiobuttons reactively - shiny) yesterday but perhaps it was too messy to get a response. I have stripped the question down: why can't I get two sets of radiobuttons to update reactively:
server.R:
# Create example data
Wafer <- rep(c(1:3), each=3)
Length <- c(1,1,2,1,1,1,3,5,1)
Width <- c(3,1,6,1,1,1,1,1,6)
dd <- data.frame(Wafer, Length, Width)
shinyServer(function(input, output, session){
# Get Lengths from user input
a <- eventReactive(input$do, {
subset(dd, Wafer %in% input$wafer, select = Length)
})
# Get Widths from user input
b <- eventReactive(input$do, {
subset(dd, Wafer %in% input$wafer, select = Width)
})
#Observe and update first set of radiobuttons based on a(). Does
#render
observe({
z <- a()
updateRadioButtons(session, "length", choices = unique(z$Length), inline=TRUE)
})
#Observe and update second set of radiobuttons based on b(). Does
#not render
observe({
z <- b()
updateRadioButtons(session, "width", choices = unique(z$Width), inline=TRUE)
})
output$l <- renderDataTable({ a() })
output$w <- renderDataTable({ b() })
})
ui.R:
library(markdown)
shinyUI(fluidPage(
titlePanel("Generic grapher"),
sidebarLayout(
sidebarPanel(
numericInput("wafer", label = h3("Input wafer ID:"), value = NULL),
actionButton("do", "Search wafer"),
radioButtons("length", label="Length", choices=""),
radioButtons("width", label="Width", choices = "")
),
mainPanel(
dataTableOutput(outputId="l"),
dataTableOutput(outputId="w")
)))
)
In the above, I can only get one set of radiobuttons to reactive ("Length"). However, if I comment out the Length observe, the Width one works so my code must be OK in isolation. Maybe I'm missing something simple?
This might be a bug of the updateRadioButtons function. When selected is not set, it is replaced by the first choice. I guess this causes an error if the choices list is numeric.
To fix your problem, you can either convert your choices to characters using as.character or set selected to a random string such as "".
Using as.character is probably better as you then get your first selection automatically selected.