Function in shiny app - r

I try to use a function in shiny app.
In ui I only call the function.
ui <- fluidPage(
myfunctionvis<- testforjson(mods, corpus, myDfm)
serVis(myfunctionvis)
)
and in server side exist all the code for this function:
shinyServer(function(input, output) {
testforjson <- function(mods, corpus, myDfm){
# Find required quantities
phi <- posterior(mods)$terms %>% as.matrix
theta <- posterior(mods)$topics %>% as.matrix
# the code continues
return(json_lda)
}
}
and the error I receive is that it can't find the testforjson fuction.
How can I fix the error or include a function in server side and call to see the results in ui?

One way to do that is to create a global.R file in which you can declare variables and functions that can be seen globally in your shiny app.
So you just need to put your testforjson function in global.R.
Check this page for more details: https://shiny.rstudio.com/articles/scoping.html

Related

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.

Shiny print reactive df to console (glimpse(myreactive_df) for debugging purposes?

I'm trying to debug my Shiny app and would like to view a reactive dataframe with e.g. glimpse(df).
Initially I tried to create a breakpoint and then view the environment by my reactive df is a value not an object when used inside server.r. I also tried browser() but was not sure what it would do.
I did some searching on SO and tried various things using sink(), renderPrint() but had no success.
How can I print the contents of glimpse(some_reactive_df()) to the console when I run my app?
Calling print() from within the reactive({}) expression will do that.
library(shiny)
library(dplyr)
shinyApp(
ui <- fluidPage(
selectizeInput("cyl_select", "Choose ya mtcars$cyl ", choices = unique(mtcars$cyl)),
tableOutput("checker") # a needed output in ui.R, doesn't have to be table
),
server <- function(input, output) {
d <- reactive({
d <- dplyr::filter(mtcars, cyl %in% input$cyl_select)
print(glimpse(d)) # print from within
return(d)
})
output$checker <- renderTable({
glimpse(d()) # something that relies on the reactive, same thing here for simplicty
})
})
Assuming you provide Shiny a reason to run (and re-run) your reactive of interest, by having it be involved with a rendering in server() and linked output in ui(). This is usually the case for my debugging scenarios but it won't work unless the reactive is being used elsewhere in app.R.

call R script from Shiny App

I developed a shiny app which displays some dynamic charts. These charts are generated at execution time according to the value of some buttons. This shiny app gets the data from a raw csv which is previously treated and transformed. I got a Rscript apart from the shiny app to do all those "transformations" of the raw data. What I would like to do is to call this Rscript from the shiny app in order to be executed when the shiny app is launched.
I have already checked these links but it didn't help at all: How can I connect R Script with Shiny app in R? and this one using Source() in Shiny. I checked the Rstudio documentation too: http://shiny.rstudio.com/tutorial/lesson5/.
I think it should be something like this, being procesadoDatos.R the RScript. i just want the source command to be executed at the beginning in order to load the data as the shiny app is starting:
source("procesadoDatos.R",local = TRUE)
shinyServer(function(input, output,session) {
(renderplots, reactives elements and so on)}
The Rscript is the shiny project path as the server.R and UI.R files. I also tried including the path but it didn't work either.
Another thing I tried was to create a function which makes all the transformations and then call it from server.R file after sourcing it:
source("procesadoDatos.R",local = TRUE)
generate_data(ticketsByService_report10.csv)
Being generate_data this function defined in the RScript:
generate_data <- function(csv_file) {
(all those transformation, data frame an so on)}
In all cases I got the same error saying that the data frames which are generated in the RScript aren't found.
Does anyone know what is wrong? Thanks in adavance
Scoping in Shiny
All this largely depends on where exactly you call source(). If you need the data to be found from within both the UI and the server function, you put source() outside the app.
If you place source() inside the server function, the UI won't be able to find any object created by the script. If you put this inside a render function, the objects are only visible inside that render function. See also Scoping rules for Shiny
Note that if you have separate server.R and ui.R files and you want the UI to find the objects created by the script, you should add a global.R file to your app directory. The source() command then goes in the global.R file.
A small example:
source('testScript.R')
shinyApp(
fluidPage(
selectInput("cols", "pick columns",
choices = names(x)),
dataTableOutput("what")),
function(input, output, session){
output$what <- renderDataTable(x)
}
)
and testScript.R contains one line:
x <- iris
The key here is:
the script actually has to create these objects
the script should be sourced in the correct spot.
So if you can do the following:
shinyApp(
fluidPage(
selectInput("cols", "pick columns",
choices = names(x)),
dataTableOutput("what")),
function(input, output, session){
source('testScript.R', local = TRUE)
output$what <- renderDataTable(x)
}
)
you get an error about not being able to find x. That's normal, because x is now only defined inside the environment of the server function.
You still can do this though:
shinyApp(
fluidPage(
dataTableOutput("what")),
function(input, output, session){
source('R/testScript.R', local = TRUE)
output$what <- renderDataTable(x)
}
)
Note how x is only needed inside the server function, not inside the UI.
Using functions
For functions, the same thing applies. You put the function definition in a script and source it like before. A function is nothing else but an object, so the script essentially creates a function object that then can be found using the exact same scoping rules.
Keep in mind though that this function should return something if you want to use the result of the function. So put this trivial example in testScript.R:
myfun <- function(x){
tmp <- iris[x]
return(tmp)
}
And now you can do the following:
source('testScript.R', local = TRUE)
shinyApp(
fluidPage(
selectInput("cols", "pick columns",
choices = names(myfun())),
dataTableOutput("what")),
function(input, output, session){
output$what <- renderDataTable(myfun(input$cols))
}
)
This doesn't work any longer if you put the source() inside the server function. The UI side won't be able to see myfun() any more.
rm(list = ls())
shinyApp(
fluidPage(
selectInput("cols", "pick columns",
choices = names(myfun())),
dataTableOutput("what")),
function(input, output, session){
source('R/testScript.R', local = TRUE)
output$what <- renderDataTable(myfun(input$cols))
}
)
# Error in myfun() : could not find function "myfun"

display of 'sync' (mapview) 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. After figuring how to display mapview object in shiny, I tried to integrate sync in 'shiny', but got the following error: Error in slot(x, "map") : no slot of name "map" for this object of class "shiny.tag.list" . Does it mean sync does not have map object, therefore, it is not possible to integrate sync or latticeView with shiny? If so, I guess there should be workaround solutions and my ears are all open. This is a nice feature to have access from Shiny and allows to do some interesting things. Greatly appreciate any suggestions. Here is the sample reproducible code:
library(shiny)
library(mapview)
ui <- fluidPage(
mapviewOutput("samplemap"),
p()
)
server <- function(input, output, session) {
output$samplemap <- renderMapview({
m1 <- mapview(gadmCHE,zcol="ID_1")
m2 <- mapview(gadmCHE,zcol="OBJECTID")
sync(m1,m2)
})
}
shinyApp(ui, server)
We have discussed making the return value from sync an htmlwidget. Currently, sync returns a htmltools::tagList of the leaflet maps. Inserting tags into shiny will be a little different than inserting mapview. I'll try to explain in code below.
library(mapview)
m1 <- mapview(gadmCHE,zcol="ID_1")
s1 <- sync(m1,m1)
library(shiny)
# if not dynamically adding maps
# we can just insert as ui
shinyApp(
ui = s1,
server = function(input,output){}
)
# if there is a need to create the maps after UI
# then we will need to handle differently
# since sync gives us tags instead of an htmlwidget
shinyApp(
ui = uiOutput("syncmap"),
server = function(input,output){
output$syncmap = renderUI({
s1
})
}
)

Shiny - Create reactive function from user string input

I'm writing shiny app and I want to create mathematical functions from user input - There is textInput where user writes a function, e.g x^2, sin(x)+5 etc. Then, I want to plot this function so I have to concatenate string from textInput and 'function(x)' statement to get R function. As far as I know, I need to have reactive variable which contains the R function. I came up with that:
func<-reactive(
bquote(function(x){ .(parse(text = input$fun)[[1]])}), quoted = TRUE
)
where input$fun is id of textInput. This solution doesn't work and I have no other idea.
You can use f<-function(x) {eval(parse(text=input$func))} to transform the input into a function.
Fron #JoeCheng:
While this certainly works, I'd caution anyone reading this to only use eval() on user input if the app will only be run locally. Apps that do this are not safe to deploy on a server because a user could feed in whatever code they want, for example system("rm -rf ~")
For example, in a shiny app:
app.R
library(shiny)
ui <- shinyUI(fluidPage(
mainPanel(textInput("func", "Function:", ""),
submitButton("Plot!"),
plotOutput("plot")
)
))
server <- function(input, output, session) {
output$plot<-renderPlot({
f<-function(x) {eval(parse(text=input$func))}
x<-1:10
plot(x,f(x))
}
)
}
shinyApp(ui = ui, server = server)
Would give you this:

Resources