Shiny - Create reactive function from user string input - r

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:

Related

How to avoid wrapping everything in observeEvent() when passing URL parameters in shiny?

I know that using something like this code:
library(shiny)
ui <- fluidPage(
mainPanel(
textOutput("Query_String")
)
)
server <- function(input, output, session) {
observeEvent(session$clientData$url_search,{
Query <- session$clientData$url_search
output$Query_String <- renderText(Query)
# Long list of operations dependant on the parameters passed in the URL
})
}
shinyApp(ui = ui, server = server)
Can enable me to read parameters into my shiny app via URL queries. However it seems like I basically have to wrap my whole server content into one big observe() or observeEvent() to create the needed reactive context.
Is there any way to avoid this?
To avoid recalculating everything if just a single item changed, one wants to create multiple separate observes instead of just a big one. Long code should be refactored in functions e.g. process_query keeping the server function small, allowing to read the overall structure. Important intermediate results can be refactored in their own reactive values (here query). output$Query_String doesn't need to be nested in another reactive context.
process_query <- function(url) {
# many steps to process the url
return(url)
}
server <- function(input, output, session) {
query <- reactive(process_query(session$clientData$url_search))
output$Query_String <- renderText(query())
}

How to run user input as R code in a Shiny app?

I want to create a shiny application that has an input for writing some R function or Command, reads it through the ui.R then passes it to the server.R that executes that R command to display the results.
I spent hours searching about some example but couldn't find anything, I already know how to create Shiny apps using ui and server and pass the input values to server and work with them, but I have no idea if it's possible to create a shiny app like R where you can write the commands and return the results, any example or help would be appreciated.
Letting users run code in your app is bad practice, since it comes with great security risks. However, for development you might want to check this function from the shinyjs package by Dean Attali.
Example from the link:
library(shiny)
library(shinyjs)
shinyApp(
ui = fluidPage(
useShinyjs(), # Set up shinyjs
runcodeUI(code = "shinyjs::alert('Hello!')")
),
server = function(input, output) {
runcodeServer()
}
)
Some examples of why it is not such a good idea to include when deploying your app:
Try the input:
shinyjs::alert(ls(globalenv()))
or
shinyjs::alert(list.files())
I was able to find an alternative solution that doesn't require shinyjs -- wanted to restate Florian's concern that in general it is not a good thing (not secure) to let users run code in your Shiny app. Here is the alternative:
library(shiny)
library(dplyr)
ui <- fluidPage(
mainPanel(
h3("Data (mtcars): "), verbatimTextOutput("displayData"),
textInput("testcode", "Try filtering the dataset in different ways: ",
"mtcars %>% filter(cyl>6)", width="600px"),
h3("Results: "), verbatimTextOutput("codeResults"))
)
server <- function(input, output) {
shinyEnv <- environment()
output$displayData <- renderPrint({ head(mtcars) }) # prepare head(mtcars) for display on the UI
# create codeInput variable to capture what the user entered; store results to codeResults
codeInput <- reactive({ input$testcode })
output$codeResults <- renderPrint({
eval(parse(text=codeInput()), envir=shinyEnv)
})
}
shinyApp(ui, server)

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"

reactivity and rhandsontable

I have recently discovered the rhandsontable package in r and it will be very useful in some of my r shiny projects. I have slightly modified what I saw here Get selected rows of Rhandsontable as a little tester for what I will use this package for.
I want to be able to let users change values of the data frame from within r using the rhandsontable package.So here I want df[1,1] to update each time I change that value. I am just a bit confused when it comes to wrapping a reactive function around render functions especially the renderRHandsontable function. I have used reactive functions with plotting but this is a bit different.
library(shiny)
library(rhandsontable)
ui=fluidPage(
rHandsontableOutput('table'),
verbatimTextOutput('selected'),
verbatimTextOutput("tr")
)
server=function(input,output,session)({
a<-c(1,2)
b<-c(3,4)
c<-rbind(df1,df2)
df1<-data.frame(df3)
#need reactive function around the following
output$table=renderRHandsontable(
rhandsontable(df1,selectCallback = TRUE,readOnly = FALSE)
)
output$selected=renderPrint({
cat('Selected Row:',input$table_select$select$r)
cat('\nSelected Column:',input$table_select$select$c)
cat('\nSelected Cell Value:',input$table_select$data[[input$table_select$select$r]][[input$table_select$select$c]])
df1[input$table_select$select$r,input$table_select$select$c]<-input$table_select$data[[input$table_select$select$r]][[input$table_select$select$c]]
})
#need reactive function around the following
output$tr <- renderText({
df1[1,1]
})
})
# end server
shinyApp(ui = ui, server = server)
It is an interesting area that will open up a lot in my shiny apps for users to play around with.
Thanks
Your code here is not reproducible. In the beginning of your server function, you used rbind() on df1 and df2when neither of these objects exist yet. R will throw an error (and it should!)
Because of that I will have to assume that your data frame is in fact the following:
a<-c(1,2)
b<-c(3,4)
c<-rbind(a,b)
df1<-data.frame(c)
To bind the reactivity output from Rhandsontable to your textOutput, you can use the observe() function from Shiny or even better, the handy hot_to_r function from rhandsontable itself. This function converts the handsontable data to R object.
Without changing your ui function, this will be your server function:
server <- function(input,output,session)({
a<-c(1,2)
b<-c(3,4)
c<-rbind(a,b)
df1<-data.frame(c)
output$table<-renderRHandsontable(
rhandsontable(df1)
)
#use hot_to_r to glue 'transform' the rhandsontable input into an R object
output$tr <- renderText({
hot_to_r(input$table)[1,1]
})
})
Then proceed to call your Shiny app as usual: shinyApp(ui = ui, server = server) and your output$tr now reacts to any edits on your table.

How can a shiny app recognize when a complete word has been typed into a text input?

In Shiny, text input can be provided by the user. When a user is typing, I want to executed server side code, but only once a complete word has been typed. Can I execute whenever "space" is entered?
I don't know any packages that would actually check for the entire word. As you can imagine other languages probably will need to be included in there too. Given an example with an activation if a string has a space you can do the following: Note that the space doesn't have to be after something is typed and will activate if there are any spaces in the string. To include more test cases I suggest you play around with regexpr, library(stringr), library(stringi). Have a look R Programming/Text Processing for some examples
rm(list = ls())
library(shiny)
ui =(pageWithSidebar(
headerPanel("Words With Spaces"),
sidebarPanel(
textInput("my_text", "Type something (will activate if has space):", "")),
mainPanel(textOutput("text"))
))
server = function(input, output, session){
output$text <- renderText({
if(is.na(is.null(input$my_text)) || is.null(input$my_text)){return()}
if(regexpr(" ",input$my_text)[1] > 0){input$my_text}
})
}
runApp(list(ui = ui, server = server))

Resources