Render table R Shiny upon action button - r

I have been using R for about a year but am only a few weeks into Shiny. I have some code which calls an API and spits out a nice tables of results which I would like to use in a Shiny App - with the API being called when an action button is clicked.
I've been trouble shooting this for a few days but can't figure it out, below are a few of the things I have tried.
If I remove the action button, the API calls and displays as soon as the app is opened.
Replacing the API with simple text shows the text when the button is clicked.
Rendering the table inside the action results in the UI wondering where the table is (as button as not been pressed) and giving an error.
The API contains sensitive info so I have removed some details added a typical return (it returns Json to the browser when URL is visited).
Any ideas on what i might be missing?
API return
{"meta":{"request":{"granularity":"Monthly","main_domain_only":false,"format":null,"domain":"cnn.com","start_date":"2017-02-01","end_date":"2017-02-28","limit":null,"country":"world"},"status":"Success","last_updated":"2017-04-30"},"visits":[{"date":"2017-02-01","visits":100000`}]}
UI.r
library(shiny)
shinyUI(fluidPage(
headerPanel(actionButton("do", "Click Me")),
mainPanel(dataTableOutput("mytable"))
))
Server.r
library(shiny)
function(input, output) {
#Call API, flatten Json return
Visits_Final<- eventReactive(input$do, {
Results<- paste0("https://api.com/",
"site.com",
"apikey=***") %>%
map(fromJSON, flatten = FALSE)
#Transform into DF
visits_temp= data.frame(date=NA,visits=NA,ID=NA)
for(i in 1:1){
DF_L<- as.data.frame(Results[[i]]$visits)
ID <- (rep(i, nrow(DF_L)))
DF_L<- cbind(DF_L, ID)
Visits_Final<-rbind(visits_temp, DF_L)}})
#Output to UI
output$mytable <- renderDataTable({Visits_Final()})
}
Thanks in advance!
Edits
for(i in 1:i){
As per BigDataScientist comment, changed to
for(i in 1:1){
Code comments added
System info added:
R 3.3.2
R Studio Version 1.0.143
OS Sierra 10_12_3

Solved - In the Server file I changed eventReactive to observeEvent
Honestly, not 100% understanding this documentation but it did help
Shiny: what is the difference between observeEvent and eventReactive?
Feel free to comment with similar problems.

Related

R: Data Frame launching manually works well, in shiny is incomplete

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.

R Shiny Dashboard - Loading Scripts using source('file.R')

Introduction
I have created an R shiny dashboard app that is quickly getting quite complex. I have over 1300 lines of code all sitting in app.R and it works. I'm using RStudio.
My application has a sidebar and tabs and rather than using modules I dynamically grab the siderbar and tab IDs to generate a unique identifier when plotting graphs etc.
I'm trying to reorganise it to be more manageable and split it into tasks for other programmers but I'm running into errors.
Working Code
My original code has a number of library statements and sets the working directory to the code location.
rm(list = ls())
setwd(dirname(rstudioapi::getActiveDocumentContext()$path))
getwd()
I then have a range of functions that sit outside the ui/server functions so are only loaded once (not reactive). These are all called from within the server by setting the reactive values and calling the functions from within something like a renderPlot. Some of them are nested, so a function in server calls a function just in regular app.R which in turn calls another one. Eg.
# Start of month calculation
som <- function(x) {
toReturn <- as.Date(format(x, "%Y-%m-01"))
return(toReturn)
}
start_fc <- function(){
fc_start_date <- som(today())
return(fc_start_date)
}
then in server something like this (code incomplete)
server <- function(input, output, session) {
RV <- reactiveValues()
observe({
RV$selection <- input[[input$sidebar]]
# cat("Selected:",RV$selection,"\r")
})
.......
cat(paste0("modelType: ",input[[paste0(RV$selection,"-modeltype")]]," \n"))
vline1 <- decimal_date(start_pred(input[[paste0(RV$selection,"-modeltype")]],input[[paste0(RV$selection,"-modelrange")]][1]))
vline2 <- decimal_date(start_fc())
.......
Problem Code
So now when I take all my functions and put them into different .R files I get errors indicating the functions haven't been loaded. If I load the source files by highlighting them and Alt-Enter running them so they are loaded into memory then click on Run App the code works. But if I rely on Run App to load those source files, and the functions within them, the functions can't be found.
source('./functionsGeneral.R')
source('./functionsQuote.R')
source('./functionsNewBusiness.R')
source('./ui.R')
source('./server.R')
shinyApp(ui, server)
where ui.R is
source('./header.R')
source('./sidebar.R')
source('./body.R')
source('./functionsUI.R')
ui <- dashboardPage(
header,
sidebar,
body
)
Finally the questions
In what order does R Shiny Dashboard run the code. Why does it fail when I put the exact same inline code into another file and reference it with source('./functions.R')? Does it not load into memory during a shiny app session? What am I missing?
Any help on this would be greatly appreciated.
Thanks,
Travis
Ok I've discovered the easiest way is to create a subfolder called R and to place the preload code into that folder. From shiny version 1.5 all this code in the R folder is loaded first automatically.

display of mapview object in shiny

I’m trying to have two spatial plots side-by-side in shiny, and I was suggested a powerful function, sync of mapview. sync allows to have multiple maps for comparison, a great feature, but unable to figure out integrating or calling its output in shiny. I have gone through ‘mapview for shiny’ and other related links mapview/shiny. The former suggested using renderMapview and mapviewOutput, however it did not work, i.e., no map being displayed. Please see the reproducible code. Also, I tried using #map slot of mapview object in renderLeaflet and calling it via leafletOutput - did not work. In both cases, a shiny window pops up and does not display anything. However, do see the following message in the command window: Warning in spCheckObject(x) : Columns CCN_1 in attribute table contain only NA values and are dropped. - it is related to the data base and confirms that mapview command is being executed but does not provide any leads on absence of plots. Greatly appreciate suggestions or clues on displaying mapview geneated plots in shiny.
library(shiny)
library(mapview)
ui <- fluidPage(
mapviewOutput("samplemap"),
p()
)
server <- function(input, output, session) {
output$samplemap <- renderMapview({
mapview(gadmCHE)
})
}
shinyApp(ui, server)

Reading an RData file into Shiny Application

I am working on a shiny app that will read a few RData files in and show tables with the contents. These files are generated by scripts that eventually turns the data into a data frame. They are then saved using the save() function.
Within the shiny application I have three files:
ui.R, server.R, and global.R
I want the files to be read on an interval so they are updated when the files are updated, thus I am using:
reactiveFileReader()
I have followed a few of the instructions I have found online, but I keep getting an error "Error: missing value where TRUE/FALSE is needed". I have tried to simplify this so I am not using:
reactiveFileReader()
functionality and simply loading the file in the server.R (also tried in the global.R file). Again, the
load()
statement is reading in a data frame. I had this working at one point by loading in the file, then assigning the file to a variable and doing an "as.data.table", but that shouldn't matter, this should read in a data frame format just fine. I think this is a scoping issue, but I am not sure. Any help? My code is at:
http://pastebin.com/V01Uw0se
Thanks so much!
Here is a possible solution inspired by this post http://www.r-bloggers.com/safe-loading-of-rdata-files/. The Rdata file is loaded into a new environment which ensures that it will not have unexpected side effect (overwriting existing variables etc). When you click the button, a new random data frame will be generated and then saved to a file. The reactiveFileReader then read the file into a new environment. Lastly we access the first item in the new environment (assuming that the Rdata file contains only one variable which is a data frame) and print it to a table.
library(shiny)
# This function, borrowed from http://www.r-bloggers.com/safe-loading-of-rdata-files/, load the Rdata into a new environment to avoid side effects
LoadToEnvironment <- function(RData, env=new.env()) {
load(RData, env)
return(env)
}
ui <- shinyUI(fluidPage(
titlePanel("Example"),
sidebarLayout(
sidebarPanel(
actionButton("generate", "Click to generate an Rdata file")
),
mainPanel(
tableOutput("table")
)
)
))
server <- shinyServer(function(input, output, session) {
# Click the button to generate a new random data frame and write to file
observeEvent(input$generate, {
sample_dataframe <- data.frame(a=runif(10), b=rnorm(10))
save(sample_dataframe, file="test.Rdata")
rm(sample_dataframe)
})
output$table <- renderTable({
# Use a reactiveFileReader to read the file on change, and load the content into a new environment
env <- reactiveFileReader(1000, session, "test.Rdata", LoadToEnvironment)
# Access the first item in the new environment, assuming that the Rdata contains only 1 item which is a data frame
env()[[names(env())[1]]]
})
})
shinyApp(ui = ui, server = server)
Ok - I figured out how to do what I need to. For my first issue, I wanted the look and feel of 'renderDataTable', but I wanted to pull in a data frame (renderDataTable / dataTableOutput does not allow this, it must be in a table format). In order to do this, I found a handy usage of ReportingTools (from Bioconductor) and how they do it. This allows you to use a data frame directly and still have the HTML table with the sorts, search, pagination, etc.. The info can be found here:
https://bioconductor.org/packages/release/bioc/html/ReportingTools.html
Now, for my second issue - updating the data and table regularly without restarting the app. This turned out to be simple, it just took me some time to figure it out, being new to Shiny. One thing to point out, to keep this example simple, I used renderTable rather than the solution above with the ReportingTools package. I just wanted to keep this example simple. The first thing I did was wrap all of my server.R code (within the shinyServer() function) in an observe({}). Then I used invalidateLater() to tell it to refresh every 5 seconds. Here is the code:
## server.R ##
library(shiny)
library(shinydashboard)
library(DT)
shinyServer(function(input, output, session) {
observe({
invalidateLater(5000,session)
output$PRI1LastPeriodTable <- renderTable({
prioirtyOneIncidentsLastPeriod <- updateILP()
})
})
})
Now, original for the renderTable() portion, I was just calling the object name of the loaded .Rdata file, but I wanted it to be read each time, so I created a function in my global.R file (this could have been in server.R) to load the file. That code is here:
updateILP <- function() {
load(file = "W:/Projects/R/Scripts/ITPOD/itpod/data/prioirtyOneIncidentsLastPeriod.RData", envir = .GlobalEnv)
return(prioirtyOneIncidentsLastPeriod)
}
That's it, nothing else goes in the global.R file. Your ui.R would be however you have it setup, call tableOutout, dataTableOutput, or whatever your rendering method is in the UI. So, what happens is every 5 seconds the renderTable() code is read every 5 seconds, which in turns invokes the function that actually reads the file. I tested this by making changes to the data file, and the shiny app updated without any interaction from me. Works like a charm.
If this is inelegant or is not efficient, please let me know if it can be improved, this was the most straight-forward way I could figure this out. Thanks to everyone for the help and comments!

Update Shinygooglevis chart without full reload

Is it possible to change the data of a googlevis chart (any of them!) without forcing a full reload of the page/chart?
Current code that gives a very undesirable flicker when the map is being reloaded:
shinyServer(function(input, output, session) {
observe({
print("Reloading..")
invalidateLater(update_freq*1000, session)
data <- loadDataFiles()
output$gvis <- renderGvis(mapPlot(data)) //mapPlot returns a new gvisGeoChart
})
Ideally I'd just reload my markers, not the chart itself.
The googleVis Shiny bindings need to be rewritten to fix this problem. In the meantime I have prototyped some ideas here that you might want to check out; you can install it using devtools::install_github("jcheng5/googleCharts") and see the example here. It is pretty rough but you won't get the flickering and instability that currently occurs with googleVis + shiny.

Resources