Previously, I had built a shiny dashboard with chart outputs that worked just fine and looked like the following:
output$someName <- renderGvis({
input$inputButton
data <- isolate(myData(function here))
donut <- gvisDonut({...})
return(donut)
})
Since the addition of observeEvent and eventReactive, I've not been able to get it to work the same as before. Essentially, the output$someName is a chart that is dependent on multiple inputs, and each time the user clicks on the inputButton, I need renderGvis to re-evaluate. The function should NOT re-evaluate when any of the other inputs change, just when the button is pressed.
I've had some luck getting observeEvent to run on input$inputButton click, however, each time I change any of my input parameters, the query is quickly rerun without having to press the button. Any takers here?
More detailed below:
output$someName <- renderGvis({
input$inputButton
data <- isolate(dataGrabber({})) # function that takes input and returns data frame using RMySQL
isolate(simpleChart(data = data)) # simpleChart is a function to produce a gvisCalendar chart.
OK...found an answer to this if anyone ever has this problem. The issue, which for some reason I had not encountered in the past, is that the isolate function now runs regardless of whether or not the value for actionButton is 0 or not. I believe in the past, it wouldn't run until actionButton had a value greater than 0.
The simple fix was:
output$someName <- renderGvis({
input$inputButton
if (input$inputButton == 0)
return()
isolate({ code to isolate})
})
Related
I'm attempting to design a Shiny App where the user changes several inputs, then presses a "Plot" button to generate new visualizations. Currently, I have the a data object being generated in an eventReactive tied to the "Plot" button, with that data then getting fed into the renderPlot functions.
The framework seems to work, except that the plots will change whenever the inputs are changed. This often leads to errors in the plots, as different inputs load in different data. Pressing the "Plot" button after changing the inputs will cause the correct plots to render, but I'm trying to find a way to ensure that the plots don't change ever until that button is hit.
I believe the solution is a use of the "isolation" function, and I've tried that just about everywhere. However, none of these attempts have been successful. Below is a (simplified) setup of my code.
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
# several selectInput options
actionButton('plot', label = 'Plot')
)
mainPanel(
plotOutput('outputPlot', height = '3in'),
)
)
)
server <- function(input, output) {
plotData <- eventReactive(input$plot, {
# load various data and organize into a list
return(data.list)
})
outPutPlot <- renderPlot({
plot.data <- plotData()
# manipulate data based on the specific plot, then generate
return(plot)
)
}
You’re right that you’d need to isolate() all reactive dependencies other
than plotData(). Without having a complete runnable example, it’s not
possible to point out where this might have gone wrong. However, it may be
easier to wrap the renderPlot() call in bindEvent(), which will isolate
everything. You just pass the expressions you want to depend on in other
arguments.
So try something like this:
bindEvent(renderPlot({ ... }), plotData())
I webscraped 2 tables (A and B). Then I merge them by rows (rbind). When I launch it, everything is ok. When I wanna use it in shiny app there is something wrong. Below structure of tables and what shiny shows. Any suggestion? Where could be the problem? Unfortunatelly, I can not show the code, because this is for my thesis. I would be very grateful for your help.
As you can see the problem is with third column. B table has all rows with NA. After merge, all data from A table has also NA.
In shiny table is showed by renderTable.
Structure of tables A and B
I have no answer for your question, but I would like to write something and there is not enough space for this in comment section, so I will write this as answer and eventually delete later. So - I rather believe that there is something wrong with your code which you use inside shiny and would like to check this with your help. I assume you need some help with debugging, so I will post a code below:
library(shiny)
ui <- fluidPage(
tableOutput("table")
)
server <- function(input, output, session) {
my_df <- reactive({
data.frame(a = c(1, 2, 3),
b = c(4, 5, 6))
})
output$table <- renderTable({
my_df()
browser()
})
}
shinyApp(ui, server)
In the code above I have made one output (table output) and - on the server side in reactive - I'm creating data.frame. Then I use this reactive function inside my output (output$plot). However, the last line inside output$plot is function browser() which is used for debugging. You can try my code in your console and see that when you run shiny app, it immediately moving back to console (but this is "dubugging state", so console looks a little different, for example there is a button "stop" with red square which can be use to close debugging state). Please run my shiny app and when you will be back in the console, in the debugging state, type my_df() to see the data.frame object. Could you please do the same with your shiny app? I mean, could you use browser() function on the last line in your renderTable? And come back and tell if the last column contains only NA or not when displayed in the console? If not, then I would say that you are doing something different in Shiny than manually with your tables.
I have the following issue with the behaviour of R shiny's numeric input behaviour. Consider the following snippet:
ui <- basicPage(
numericInput("example","Example",value=0),
verbatimTextOutput("changelog")
)
server <- function(input,output){
output$changelog <- renderPrint(input$example)
}
shinyApp(ui,server)
Suppose that I want to update the example input field to 12345. My issue is that the default event listener would react to every keystroke. Thus the input field would be set to 1, 12,123 and 1234 before I finally get the desired value of 12345. Each numeric input set would be followed by an expensive computation - so this is a very undesirable behaviour.
What I am after is modifying this behaviour so that the event listener only reacts to the numeric input when the user hits enter or leaves the input field. I have currently two approaches to this:
Use a reactiveValue with an update actionButton so that the input is updated only when the user clicks update. I find this an inelegant solution and only shirks the original problem without solving it.
Modify the local shiny.js file directly and remove the keyup.textInputBinding event. That creates another issue with running the shiny app on other computers and it would make this modified behaviour uniform for all numericInput.
I'm wondering if anyone has a solution/suggestion to this? Preferably something that does not involve changing the local shiny.js file. I'm guessing a solution would involve using shinyjs::runjs to manually unsubscribe the keyup.textInputBinding event - but I don't know enough JavaScript to execute it.
You can slow frequent invalidation down with debounce or throttle. In your case, my first guess would be debounce: Debouncing means that invalidation is held off for millis milliseconds.
The reactive expression will only be validated until that time window has passed without a subsequent invalidation which may have an effect like this: ooo-oo-oo---- => -----------o-
In your case:
library(shiny)
ui <- basicPage(
numericInput("example","Example",value=0),
verbatimTextOutput("changelogImmediate"),
verbatimTextOutput("changelog")
)
server <- function(input,output){
exampleInput <- reactive(input$example) %>% debounce(1000)
# debouncedExampleInput <- exampleInput
output$changelogImmediate <- renderPrint(input$example)
output$changelog <- renderPrint(exampleInput())
}
shinyApp(ui,server)
I am working with shiny for R. At the beginning of my program I am creating a dataframe that is stored in reactiveValues() .
myReactiveDataframe <- reactiveValues()
myReactiveDataFrame[["df"]] <- someDataFrame
Upon interaction with the App through the user content of the dataframe is modified and then stored in reactiveValues() as well.
Something like
myReactiveDataframe[["modified"]] <- myReactiveDataFrame$df[MyReactive....]
Later on in my App I have some observe() that work with myReactiveDataframe$modified.
My Problem is: On the start of the App myReactiveDataframe$modified evaluates to NULL because it is not created yet. That means that many of the observers get triggered and crash of course because the input is NULL and not a dataframe. To prevent that I have to write a if/else at the beginning of each observe that checks if the variable of interest is.null(....
Very annoying. Any ideas how not to do that?
My code looks like
observe ({
#subset someDataframe which I need in the observeEvent()
observeEvent(input$Numbers{
#if not NULL, do something with subsetted dataframe
})
})
I have an observe() function which gets input from the ui.R. Depending on the input, I subset a dataframe which will be displayed in the app.
There is the need for further subsetting, but this field can be empty. To avoid the Unhandled Error if the selection is empty (thus, NULL) is use the observeEvent() function. If the field stays empty, there is no error raised.
There is some weird behaviour though. I print out what is selected (in my R console) observed by the observeEvent(). When I select something observed by the observeEvent() function, the selected stuff gets print out once. When I change a selection which is observed by the simple observe() and then change something in the selection observed by observeEvent() it gets printed out twice. When I change a selection observed by the observe() function and then the selection from the observeEvent() it gets printed out three times - and so forth.
So, depending on how often I change a selection observed by the observed() function I change, the observeEvent() gets executed that often.
Why is that?!
As per my comment:
subset <- reactive({
# Do your sub-setting here
if(!is.null(input$Numbers)){
#Do something else
}
# return (your_subset)
})