I'm trying to pass set of variables into select input, and use its names to expss::fre command.
I have object with column names and its labels like 'myvars':
a1_1, "Do you like apples?"
a1_2, "Do you like oranges?"
I'm using them:
selectInput(vars, "Select variable", myvars)
Then, in 'server' section i would like to use it for generating simple frequency table.
output$view <- renderTable( {
fre(input$variable)
}
The problem is that in fre I have to pass variable with dataset name:
fre(data$a1_1)
So I tried with eval, quo, !!, paste0("data$",input$vars) and more, but didn't succeed.
when I try with switch:
switch(input$vars, "a1_1"=fre(data$a1_1), "a1_2"=fre(data$a1_2))
It works fine, but I need more flexible solution.
How to do this well?
The following code should do the trick:
output$view <- renderTable({
fre(data[[input$vars]])
})
Related
A simple way to replicate this issue:
shinyApp(
ui = fluidPage(
textOutput("helloJohn"),
br(),
textOutput("helloJacob"),
br(),
textOutput("helloJoe")),
server = function(session, input, output) {
for(name in c("John", "Jacob", "Joe")) {
output[[paste0("hello", name)]] <- renderText({paste0("hello ", name, "!")})
}
})
The intention of this code is to have the text "Hello John", "Hello Jacob", "Hello Joe" appear on the page without having to reuse the renderText chunk. However, while it seems that the output names get set correctly, when being rendered it seems that name gets set to the last value in the for loop, resulting in all the names being "Joe":
I assume this is due to the way Shiny sets up a dependency graph, however name is not a reactive variable, it is available during the initialization. Is there a way I can force evaluation of name inside the for loop, similar to Bang Patterns in Haskell?
You can wrap what's in the for loop in local and create a local variable name2 that receives name.
for(name in c("John", "Jacob", "Joe")) {
local({
name2 <- name
output[[paste0("hello", name2)]] <- renderText({paste0("hello ", name2, "!")})
})
}
Additional info and inspiration for this answer here.
I want two different events to trigger an update of the data being used by various plots / outputs in my app. One is a button being clicked (input$spec_button) and the other is a point on a dot being clicked (mainplot.click$click).
Basically, I want to listed for both at the same time, but I'm not sure how to write the code. Here's what I have now:
in server.R:
data <- eventReactive({mainplot.click$click | input$spec_button}, {
if(input$spec_button){
# get data relevant to the button
} else {
# get data relevant to the point clicked
}
})
But the if-else clause doesn't work
Error in mainplot.click$click | input$spec_button :
operations are possible only for numeric, logical or complex types
--> Is there some sort of action-combiner function I can use for the mainplot.click$click | input$spec_button clause?
I know this is old, but I had the same question. I finally figured it out. You include an expression in braces and simply list the events / reactive objects. My (unsubstantiated) guess is that shiny simply performs the same reactive pointer analysis to this expression block as to a standard reactive block.
observeEvent({
input$spec_button
mainplot.click$click
1
}, { ... } )
EDIT
Updated to handle the case where the last line in the expression returns NULL. Simply return a constant value.
Also:
observeEvent(c(
input$spec_button,
mainplot.click$click
), { ... } )
I've solved this issue with creating a reactive object and use it in event change expression. As below:
xxchange <- reactive({
paste(input$filter , input$term)
})
output$mypotput <- eventReactive( xxchange(), {
...
...
...
} )
Here's the solution I came up with: basically, create an empty reactiveValues data holder, and then modify its values based on two separate observeEvent instances.
data <- reactiveValues()
observeEvent(input$spec_button, {
data$data <- get.focus.spec(input=input, premise=premise,
itemname=input$dropdown.itemname, spec.info=spec.info)
})
observeEvent(mainplot.click$click, {
data$data <- get.focus.spec(input=input, premise=premise, mainplot=mainplot(),
mainplot.click_focus=mainplot.click_focus(),
spec.info=spec.info)
})
This can still be done with eventReactive by putting your actions in a vector.
eventReactive(
c(input$spec_button, mainplot.click$click),
{ ... } )
The idea here is to create a reactive function which will execute the condition you want to pass in observeEvent and then you can pass this reactive function to check the validity of the statement. For instance:
validate_event <- reactive({
# I have used OR condition here, you can use AND also
req(input$spec_button) || req(mainplot.click$click)
})
observeEvent(validate_event(),
{ ... }
)
Keep Coding!
Goal
To upload a file in a Shiny app that reads the data, name the variables (columns) and do some data analysis before presenting plot output
Reference Shiny App
I am using this app from Shiny gallery as a reference: enter link description here
What I have tried:
I want to use the uploaded data in many outputs after doing different analyses. So, instead of reading file inside renderTable or renderPlot, I read it in server function:
server <- function(input, output) {
inFile <- reactive({input$file1})
sdf <- reactive({read.csv(inFile()$datapath, header=F)})
colnames(sdf()) <- c('Vehicle.ID', 'Time', 'Vehicle.class.no', 'Vehicle.type2',
'Vehicle.Length', 'Lane', 'Preceding.Vehicle.ID', 'Spacing','Spacing2', 'State',
'svel.mps', 'deltaV.mps', 'sacc', 'lane.change') }
Error
But when I run this app I get:
shiny::runApp('app-CC')
Listening on http://127.0.0.1:7484
Error in colnames(sdf()) <- c("Vehicle.ID", "Time", "Vehicle.class.no", :
invalid (NULL) left side of assignment
Question
How can I fix this error? I don't want to read the same file again in every render* function. Are there any online examples of shiny apps where a new file is read, column names are defined and then some analysis is done before using the render* functions?
You'd be better off assigning the column names during the read.csv
server <- function(input, output) {
inFile <- reactive({input$file1})
sdf <- reactive({
read.csv(inFile()$datapath, header=F, col.names = c('Vehicle.ID', 'Time', 'Vehicle.class.no', 'Vehicle.type2',
'Vehicle.Length', 'Lane', 'Preceding.Vehicle.ID', 'Spacing','Spacing2', 'State',
'svel.mps', 'deltaV.mps', 'sacc', 'lane.change')
)
})
}
Alternatively I believe you can perform multiple operations in the reactive block as long as you return the final object
server <- function(input, output) {
inFile <- reactive({input$file1})
sdf <- reactive({
dd<-read.csv(inFile()$datapath, header=F)
colnames(dd) <- c('Vehicle.ID', 'Time', 'Vehicle.class.no', 'Vehicle.type2',
'Vehicle.Length', 'Lane', 'Preceding.Vehicle.ID', 'Spacing','Spacing2', 'State',
'svel.mps', 'deltaV.mps', 'sacc', 'lane.change')
)
dd
})
}
An alternative is to use an actionButton and then to check for the validity of the files when you upload them. Lots of observeEvent is probably appropriate for firing off when something is "triggered," like a file being uploaded or a button being pressed. In addition, to make a chain of changes, it's probably best to have an "update" reactiveValue() thing to fire based on flags (which, I admit, is kind of messy, but works with Shiny since it doesn't have a proper callback framework like JS.)
I am trying to get values from inputs with IDs like "imp1", "imp2", "imp3",...
There's no limit to the amount of 'imps' so it cannot be done manually.
What i thought is that i could make a list called "impIDList" that gets the amount of 'imps' and assign a String to each entry of the list as "imp1", "imp2",...
The problem is server.R doesn't use the String's to process the inputs but it uses only the imp1, or imp2 or imp3... without the quotes.
That happens when i get to:
impIDList<-for(i in 1:numImp){
impID<-paste("imp",toString(i))
imps[[i]]<-input$impID
}
because impID (3rd line) is "imp1", not to imp1.
ui.R
(...)
output$imps<-renderDataTable({
numImp<-(input$num_imp)
imps<-list()
impIDList<-for(i in 1:numImp){
impID<-paste("imp",toString(i))
imps[[i]]<-input$impID
}
})
(...)
If more information is needed (or the question is not in the correct format...) please vote down , but at least say something...I kind of need some help...
Ok, i solved it.
server.R uses inputs like " input$something " and creates outputs like " output$something ".
ui.R displays the outputs like xoutput("something"), and the inputs are created in the widget as, for example:
numericInput({
inputid="imp1",
label="blah blah"
)}
As i had inputs id's like "imp1", "imp2", "imp3",... and needed server.R to use them as input$imp1, input$imp2, input$imp3,... (without the quotes) i only used a parse inside a for loop. I saved the inputs in a list called "imps", another input called "num_imps" got the number of numericInputs.
The code looks like
v_imps<-reactive({
numImp<-(input$num_imp)
imps<-list(c("a","b"))
for(i in 1:numImp){
impID<-paste("imp",toString(i),sep = "")
imps[[1]][i]<-eval(parse(text = paste("input$",impID,sep = "")))
}
imps
})
I was going to put images of what i've done but i have not enough rep.
Thanks anyway
Hope someone can help me with this.
Let's say there is a function "example" which is something like
##function from a package
example<-function(f){
#does something
cat("step 1 done....")
# etc etc
cat("step 2 done....")
return(some_data_frame)
}
##server ui code
example2<-reactive({
if(input$some_action_button==0)
return()
result<-isolate(example(input$f1))
return(result)
})
output$f2<-renderPrint({
example2()
})
Is there some way to capture the "cat" outputs from the function into renderPrint, periodically? Assuming that this is a long function to process and it would be nice for the user to get some feedbabk. invalidateLater does not work for things that are already within a function (at least it seems that way when I tried it here).
Also, as a secondary problem, writing the code in the above manner would cause renderPrint to capture both the "cat" and the data.frame together, possibly because of the "return".
If anyone could point me in the right direction, it would be most helpful! Thanks!
First of, great question I've been thinking a lot about this.
Since shiny is single threaded it's a bit tricky capturing function output and displaying it in shiny from what i know.
A work around for this would be using a non blocking file connection and running the function you want to capture the output from in the background while reading the file for the function output (Check the edit history to see how to do this).
Another way of doing this would be overriding the cat function to write to stderr (simply switching cat with message) and capture the function output like this:
library(shiny)
library(shinyjs)
myPeriodicFunction <- function(){
for(i in 1:5){
msg <- paste(sprintf("Step %d done.... \n",i))
cat(msg)
Sys.sleep(1)
}
}
# Override cat function
cat <- message
runApp(shinyApp(
ui = fluidPage(
shinyjs::useShinyjs(),
actionButton("btn","Click me"),
textOutput("text")
),
server = function(input,output, session) {
observeEvent(input$btn, {
withCallingHandlers({
shinyjs::text("text", "")
myPeriodicFunction()
},
message = function(m) {
shinyjs::text(id = "text", text = m$message, add = FALSE)
})
})
}
))
This example is mostly based on this question by daattali.