Reputation: 574
Original question posted here: Shiny reactive Unexpected Behavior
The question is being re-posted here in an attempt to improve the original question posted previously in the link provided above as I was not able to receive any assistance.
Objective: In brief, the purpose of this app is to allow the user to perform search, filter, and slice and dice the data, provided in from of a dataframe, based on various inputs provided to the user.
As part of the server
function, a reactive function named index
has been defined to look up the indices corresponding to the user's inputs. The reactive function,index
, uses grep
and which
functions to locate the respective indices in the dataframe df
.
I have included a reproducible code and tried to include comments, where appropriate.
Further explanation about the code:
The title of this question is just my own speculation and it's based on the assumption that the code within index
is correct. there might be a fundamental issue with the code within index
and not the reactivity of the index
function necessarily. In order to test this, as part of the server
function, I have included a function printIndex
in order to print the results of index
to make sure that it works properly.
I have personally tried printing the results of ind.j
, ind.c
, ind.l
,ind.d
, ind.s
, and ind.all
each one individually to the console and they seemed to all produce the right results. However, when I test the results of ind
it's not quite what I expect so I'm wondering if it's the reactivity or the line of code that's problematic. What the ind
intends to do is to take the list of all the looked-up indices, stored in ind.all
, and applies the intersect
function recursively to find the common elements from all the sublists in ind.all
.
As I mentioned above, the index
function works fine for individual filters. However, when I enter values for all the indices, as a user, the function does not update to the correct list of indices as expected. For example, you can try inputting "application" in the Job textInput, "Gas Drive Global" in the Company selectizeInput, and "Calgary" in the Location textInput at the same time and hit Search!. You will see that the data table does not return any results while this clearly corresponds to the 1st row of the dataframe df
.
#Load required packages
ListofPackages= c('shiny','ggplot2','scales')
lapply(ListofPackages,require,character.only=TRUE)
#Define the dataframe on which the search will be performed
df <- data.frame(Job=c('Applications Engineer ââ¬â Gas Drive',
'Engineer, Operations',
'Project Engineer',
'Project Engineer (Oil & Gas)',
'Project Engineer',
'Junior Engineer',
'Engineer, Operations',
'Research and Development (R&D) Junior Engineer',
'JUNIOR QUALITY ENGINEER',
'Junior Systems Design and Support Engineer',
'Mechanical Engineer Calgary, AB',
'Applications Engineer',
'Project Engineer',
'Pipeline Engineer',
'Development Engineer',
'Specialist Engineering Finance',
'Mechanical Engineer - Sudbury',
'Project Cost Analyst (12 month term)',
'Project Controls Functional Analyst',
'Project Controls Professionals'),
Company=c('Gas Drive Global',
'Agrium Wholesale',
'City of Calgary',
'Stantec',
'Shell',
'Canadian National Railway',
'Pembina Pipeline Corporation',
'Velan Inc.',
'G.W. Goudreau Personnel Services Ltd',
'Stratified Automotive Controls',
'Pason Systems Corp.',
'Howden',
'Plains Midstream Canada',
'Amec Foster Wheeler',
'Red Bend Software',
'Canadian Pacific',
'GENIVAR',
'Thales',
'AltaGas Ltd.','BEMAC Construction Corp.'),
Location=c('Calgary',
'Redwater',
'Calgary',
'Edmonton',
'Sarnia',
'Montréal',
'Calgary',
'Montréal',
'Windsor',
'Vancouver',
'Calgary',
'Winnipeg',
'Calgary',
'Calgary',
'Engineer',
'Calgary',
'Greater Sudbury',
'Ottawa',
'Calgary',
'Calgary'),
Posted=c(1,
1,
1,
2,
2,
1,
4,
5,
6,
4,
1,
5,
5,
3,
1,
1,
15,
1,
1,
13),
Source=c('Indeed',
'Indeed',
'Indeed',
'Indeed',
'Indeed',
'Indeed',
'Indeed',
'Indeed',
'Indeed',
'Indeed',
'Indeed',
'Indeed',
'Indeed',
'Indeed',
'Indeed',
'Indeed',
'Indeed',
'Indeed',
'Indeed',
'Indeed'),
url=c('http://ca.indeed.com/rc/clk?jk=2371e16aab902f84',
'http://ca.indeed.com/rc/clk?jk=428facb738edd397',
'http://ca.indeed.com/rc/clk?jk=e15d8fe4d362279b',
'http://ca.indeed.com/rc/clk?jk=28c1464fd4e28b24',
'http://ca.indeed.com/rc/clk?jk=736ec57bf6902b93',
'http://ca.indeed.com/rc/clk?jk=bdc9999eae922645',
'http://ca.indeed.com/rc/clk?jk=3a4588fca0e600b1',
'http://ca.indeed.com/rc/clk?jk=71f1abcd100850c6',
'http://ca.indeed.com/cmp/G.W.Goudreau-Personnel-Services-Ltd/jobs/Junior-Quality-Engineer-3237601a1f3d3abc?r=1',
'http://ca.indeed.com/cmp/Stratified-Automotive-Controls/jobs/Junior-System-Design-Support-Engineer-1d916a435e69b8ce?r=1',
'http://ca.indeed.com/rc/clk?jk=fca9a784a37ece8a',
'http://ca.indeed.com/rc/clk?jk=b2d0975c638c03a8',
'http://ca.indeed.com/rc/clk?jk=c92725272c5f9ced',
'http://ca.indeed.com/rc/clk?jk=cd97c050df64787c',
'http://ca.indeed.com/rc/clk?jk=e6e278ed52532f73',
'http://ca.indeed.com/rc/clk?jk=a1f14d52c7798d7b',
'http://ca.indeed.com/rc/clk?jk=112350d5e020241f',
'http://ca.indeed.com/rc/clk?jk=a324c2dcade7dc5c',
'http://ca.indeed.com/rc/clk?jk=77895efdf28ad6fa',
'http://ca.indeed.com/cmp/BEMAC-Construction-Corp./jobs/Project-Control-Professional-90796e764f064a51?r=1'))
server <- function(input,output,session){
#Server-side search for the choices argument of selectizeInput in ui.R
updateSelectizeInput(session, 'c', choices = as.character(df$Company), server = TRUE)
#Create a reactive function to look up the indices correponding to the user's inputs
index <- reactive({
ind.j <- if(input$j=='') NULL else grep(input$j,df[,'Job'],ignore.case = T)
ind.c <- {tmp<-lapply(input$c, function(x) {which(df[,'Company']==x)}); Reduce(union,tmp)}
ind.l <- if(input$l=='') NULL else grep(input$l,df[,'Location'],ignore.case = T)
ind.d <- which(df[,'Posted']<=input$d)
ind.s <- {tmp<-lapply(input$s, function(x) {which(df[,'Source']==x)}); Reduce(union,tmp)}
ind.all <- list(ind.j,ind.c,ind.l,ind.d,ind.s)
ind <- if(is.null(ind.s)) NULL else {ind.null<- which(lapply(ind.all,is.null)==TRUE) ;Reduce(intersect,ind.all[-ind.null])}
})
#Create a reactive function to return the search results by returning the indices looked up in the index function above
search <- reactive({
df[index(),]
})
#Print the results of the index function above to test if it works properly
output$printIndex <- renderUI({
list(index())
})
#Send the searchresult table to ui.R to print the results of the search function above
output$searchresult <- renderDataTable({
input$action6 #triggered only when button is pressed
if(input$action6==0) return()
else{isolate({
transformed <- transform(search(), Link = paste('<a href = ', shQuote(url), '>', 'Click</a>'))
transformed <- transformed[,c(1:3,5,7,4,6)] #Rearrange columns
transformed[-7] #Remove last column
})
}
}, option=list(autoWidth=FALSE,pageLength=100,
columnDefs = list(list(targets =c(5,6) -1, searchable = FALSE),list(sWidth=c("100px")))))
}
ui <- shinyUI(fluidPage(
#Display datatable filters on top
tags$head(tags$style("tfoot {display: table-header-group;}")),
#Add a title
h1('Power Search'),
#Use the Sidebar layout
sidebarLayout(
sidebarPanel(
#Add various fields for the user in order to search the dataframe
h5('Note: Running the app takes a little while at startup.'),
helpText('Job:'),
textInput('j',''),
helpText('Company:'),
selectizeInput('c','',choices=NULL,multiple=T),
helpText('Location:'),
textInput('l',''),
sliderInput('d','Posted (days ago)',min = 0,max = 60,step = 5,value = 60),
checkboxGroupInput('s','',choices = c('Indeed','Glassdoor'),selected = c('Indeed','Glassdoor')),
actionButton('action6','Search!')
),
mainPanel(
#Display results
htmlOutput('printIndex'),
dataTableOutput('searchresult')
)
)
))
shinyApp(ui = ui, server = server)
Upvotes: 3
Views: 1653
Reputation: 30425
The problem you have is with the which
function:
> which(rep(FALSE, 5))
integer(0)
You can change:
ind <- if(is.null(ind.s)){
NULL
}else{
ind.null<- which(lapply(ind.all,is.null)==TRUE)
Reduce(intersect,ind.all[-ind.null])
}
to
ind <- if(is.null(ind.s)){
NULL
}else{
Reduce(intersect,ind.all[!sapply(ind.all,is.null)])
}
Upvotes: 4