How to fetch data from REST API periodically? - r

Background
I am currently building a „Data-Logger“ - App using R Shiny. I do have an REST - API, which returns a value, that changes over time. My goal is to create an Shiny App, in which an user can click on an actionbutton to start writing the values fetched from the api periodically (e.g. every 60 seconds) to a dataframe. The logging of the data also should be stopped, when the user clicks on another actionbutton.
Problem
My problem is writing a function that starts executing when a button is pressed, executes periodically after that and stops executing when another button is pressed.
Previous Ideas
I previously tried using invalidateLater(), but i could not achieve what i desire.
Can you guys help me out with a clever thought or idea?
Thanks in advance!

This should show how it works. invalidateLater() is the right choice. The start/stop buttons change a reactive expression that determines whether polling is on or off. That way, the reactive RestPoll expression gets notified every time it gets switched on/off and, of course, after 500 ms as long as Running() == TRUE.
library(shiny)
ui <- fluidPage(
actionButton("btnStart", "Start"),
actionButton("btnStop", "Stop"),
textOutput("outTime")
)
server <- function(input, output, session) {
Running <- reactiveVal(FALSE)
observeEvent(input$btnStart, {
Running(TRUE)
})
observeEvent(input$btnStop, {
Running(FALSE)
})
RestPoll <- reactive({
if (Running()) # IS called every time `Running` changes
invalidateLater(500, session)
# Add any REST calls here, process the results
return(Sys.time()) # deliver results
})
output$outTime <- renderText({
req(RestPoll())
})
}
shinyApp(ui, server)
You could also do it with a reactiveTimer but that would also poll and use resources when polling is not required.

Related

How to trigger data refresh automatically in R shiny dashboard

I have the below function to read data from RDS file.
# Function to get updated data
updateData <- function(forceclick = FALSE){
update_data <<- readRDS(path, "update_data.rds")
}
And, there is an action button in the UI to update data when it is triggered.
##On the UI side action button to refresh data load
actionButton("update_button",
"Data refresh")
###data refresh code on server side
observeEvent(input$update_button, {
updateData(forceclick = TRUE)
})
Here the data is refreshed when the actionButton ´input$update_button´ is triggered.
Here i am supposed to do manual refresh using the action button as shown in the sample code or manually scale down the pods and scale up.
How could the data upload be automated for eg: every morning without the need to trigger the actionButton ´input$update_button´?
Can ´invalidateLater´ be used for observeEvent like below?
###data refresh code on server side
observeEvent(input$update_button, {
invalidateLater(1000000,session)
updateData(forceclick = FALSE)
})
or could it be solved if the updateData() is executed periodically at set time which reads the .rds file?

R Shiny display app is busy in a widget

I am developing a R Shiny application involving Twitter data fetching. As the process could last some time I would like to indicate that the application is busy doing something, so the user doesn't thing the page is frozen.
In my case, I store some reactive values this way:
rv <- reactiveValues()
rv$analysisStarted <- FALSE
rv$analysisAvailable <- FALSE
Then, in UI, the user must press an actionButton in order to start processing. Then, I would like to indicate somewhere the Server is working...
observeEvent(input$analysisButton, {
rv$analysisStarted <- TRUE
rv$analysisAvailable <- FALSE
#Processing Twitter info...
rv$followersAnalysisStarted <- FALSE
rv$followersAnalysisAvailable <- TRUE
})
If, in UI.r, I place a textOutput and create the corresponding output method this way, it does NOT work:
output$text <- renderText({
if (rv$analysisStarted) {
"Server is working..."
} else if (rv$analysisAvailable) {
"Your report is ready :) "
} else {
"Enter the data to search and press analysisButton"
}
})
What I have noticed is when the analysis begins, the label changes to a gray color, but it doesn't update the text until the process is over.
What should be the proper coding of this feature?
Is it possible to redraw the text output within observeEvent?
Is it possible with the raw shiny library or requires shinyjs, which I am also using?
Any help would be grateful.
In your case, it would be helpful a progressbar to check the state. This element would be appreciate by your users to indicate the state. Unfortunately, the progress bar would have to code before the functionality. It is a trick, you see a progress bar but this object stops when the function starts.
Here is the tutorial: http://shiny.rstudio.com/gallery/progress-bar-example.html
From my point of view, the progress bar is the best way to inform the web users of the website state but it is not completely perfect. Further you can change the style of the bar with CSS to customize and select your own colors, size...

actionButton fires twice

I have a very large application with many actionButtons triggering events. I use the following logic for all my actionButtons in server.R:
observe({
if(input$myButton==0) return(NULL)
isolate({
# Code goes here
})
})
At some stage recently, the code within the isolate({}) now triggers twice whenever I click the actionButton.
It happens on all buttons within my project - and I can't think of how to debug it. Can anyone offer advice on debugging or what to look for?
For debugging purposes you could use reactive log visualizer and showcase mode:
Start with a fresh R session and run the command options(shiny.reactlog=TRUE)
Then run your app in a show case mode: runApp("yourApp", display.mode = "showcase")
At any time you can hit Ctrl+F3 (or for Mac users, Command+F3) in your web browser to launch the reactive log visualization.

Shiny Issue - Tracking User Settings in Multiuser Environment

I asked this question on the Shiny user group, but haven't been able to get a response, so I'm posting it here as well.
I have an app that needs to track a user's preference, with the possibility that several users may be using the app simultaneously. For simplicity, let's say I have a list to contain a user's settings stored within the shiny server function. It's a long list (1000 elements) that contains attributes based on the user's interaction with the app. The user can in effect change any index of this list to one of hundreds of possible settings. My initial solution was something like this:
shinyServer(function(input, output, session) {
settings <<- rep("A",1000)
observe({
input$changeSettingsButton
settings[input$changeIndex] <<- input$newSetting
})
}
Which works great unless you have multiple people using the app at the same time, because the <<- creates a global, shared variable across sessions. Is there a good way to do this?
You can use reactiveValues to store persistent user info. Something like
shinyServer(function(input, output, session) {
myReactives <- reactiveValues(settings = rep("A",1000))
observe({
input$changeSettingsButton
isolate(myReactives$settings[input$changeIndex] <- input$newSetting)
})
}
may work for you.

Execute a function in background when clicking a button with no output being changed (Shiny)

I want to be able to click a button within my Shiny App. So far so easy.
But when doing so, a function that loads, writes and then saves an excel sheet should be executed "behind the scenes" with no output changed in the App itself.
How can I do this?
Kind regards,
Martin
Yes. Try to use an Observer.
in server.R:
shinyServer(function(input, output, session) {
# other code ...
observe({
# do_something_button is your actionButton id.
if (input$do_something_button > 0) {
# perform behind the scenes analysis here.
# if you want to send a message to the client side, you can try
# something like:
message <- list(type="completed", excel_file=saved_file)
session$sendCustomMesage("background_task", message)
}
})
# other code ...
})
then write some custom javascript snippet and load it via ui.R:
Shiny.addCustomMessageHandler("background_task", function(message) {
console.log("Finished processing: " + message.excel_file);
});
In this way when the server completes the background processing, or should an error occur, you can get some feedback on the client side. Maybe you want to notify the user about an error or something.
The reference for using observe is here

Resources