I am working on a Shiny application in which there are two slider inputs. These inputted values subset a data frame differently, and the subset of that data frame is then plotted into a scatterplot.
I am trying to prevent the scatterplot from being replotted unless the user clicks a "Go!" button. To try to achieve this, I am using the isolate() function on the slider input values, so that the data frame and plot are only updated when the "Go!" button is changed.
This seems to be working okay, but I am also trying to allow the user to use the selection tool in Plotly and see the data frame rows that correspond to that selection. However, when I attempt to do so, I receive an error ("Error: object 'datInput' not found"). This line is commented in the example below:
library(shiny)
library(plotly)
ui <- shinyUI(pageWithSidebar(
headerPanel("Click the button"),
sidebarPanel(
sliderInput("val1", "Value 1:", min = 0, max = 1, value=0.5, step=0.1),
sliderInput("val2", "Value 2:", min = 0, max = 1, value=0.5, step=0.1),
actionButton("goButton", "Go!")
),
mainPanel(
plotlyOutput("plot1"),
verbatimTextOutput("click")
)
))
server <- shinyServer(function(input, output) {
set.seed(1)
dat <- data.frame(Case = paste0("case",1:15), val1=runif(15,0,1), val2=runif(15,0,1))
dat$Case <- as.character(dat$Case)
xMax = max(dat$val1)
xMin = min(dat$val1)
yMax = max(dat$val2)
yMin = min(dat$val2)
maxTemp = max(abs(xMax), abs(xMin))
observeEvent(input$goButton,
output$plot1 <- renderPlotly({
# Use isolate() to avoid dependency on input$val1 and input$val2
datInput <- isolate(subset(dat, val1 > input$val1 & val2 > input$val2))
p <- qplot(datInput$val1, datInput$val2) +xlim(0, ceiling(maxTemp)) +ylim(0,1)
ggplotly(p)
})
)
d <- reactive(event_data("plotly_selected"))
output$click <- renderPrint({
if (is.null(d())){
"Click on a state to view event data"
}
else{
#str(d()$pointNumber) #Seems to be working
datInput[d()$pointNumber,] #Error: object 'datInput' not found
}
})
})
shinyApp(ui, server)
Any ideas for a workaround for this issue would be appreciated!
EDIT:
Here is the solution as per @mlegge. I simply added the output after the user selects certain points:
library(shiny)
library(plotly)
ui <- shinyUI(pageWithSidebar(
headerPanel("Click the button"),
sidebarPanel(
sliderInput("val1", "Value 1:", min = 0, max = 1, value=0.5, step=0.1),
sliderInput("val2", "Value 2:", min = 0, max = 1, value=0.5, step=0.1),
actionButton("goButton", "Go!")
),
mainPanel(
plotlyOutput("plot1"),
verbatimTextOutput("click")
)
))
set.seed(1)
dat <- data.frame(Case = paste0("case",1:15), val1=runif(15,0,1), val2=runif(15,0,1))
dat$Case <- as.character(dat$Case)
xMax = max(dat$val1)
xMin = min(dat$val1)
yMax = max(dat$val2)
yMin = min(dat$val2)
maxTemp = max(abs(xMax), abs(xMin))
server <- shinyServer(function(input, output) {
# datInput only validated once the go button is clicked
datInput <- eventReactive(input$goButton, {
subset(dat, val1 > input$val1 & val2 > input$val2)
})
output$plot1 <- renderPlotly({
# will wait to render until datInput is validated
plot_dat <- datInput()
p <- qplot(plot_dat$val1, plot_dat$val2) + xlim(0, ceiling(maxTemp)) +ylim(0,1)
ggplotly(p)
})
d <- reactive(event_data("plotly_selected"))
output$click <- renderPrint({
if (is.null(d())){
"Click on a state to view event data"
}
else{
#str(d()$pointNumber)
datInput()[d()$pointNumber+1,] #Working now
}
})
})
shinyApp(ui, server)
