I'm trying to use Shiny to get data from a file and use this data to populate a list.
The process is pretty standard. On a server.R file, I get a vector called 'list' by reading a csv file. I want to be able to select the value from this vector with a selectInput() function. So I put an observe loop to check if the file is uploded, and if it's correct, list is created.
observe({
inFile<-input$DATA
if(!is.null(inFile)){
data = read.table(inFile$datapath, header=T,sep=";")
list=unique(data$SLE)
}else{
list=NULL
}
})
My selectInput() is like this :
output$SLE = renderUI({ selectInput('SLE1', label='Choose the item :', levels(list)) })
If I put the selectinput() in the observe loop, the select box works well, except that every time the observe loop is executed, the selectbox is reset. So, it's not a solution.
If I leave the select box out of the observe loop, list keeps the defaut value even if the data file is loaded.
I've tried to set list as a reactive value but it wasn't a success. How can I set list?
You can have the select input inside a conditional panel in UI.R itself and
use a function in place of "choices=" to retrieve the data frame as the list of choices.
One example is as below:
in ui.R:
selectInput("id", "Select Employee:", get.Employee())
Required funcion:
get.Customers <- function(input){
# YOU CAN ENTER YOUR CODE IN HERE
df_input <- input$nr
return(df_input)
}
Related
I'm making an app in Shiny which allows users to upload data or upload a save file.
If a user uploads new data then the flow looks like:
Upload Files >> Select Sheets >> Select Columns >> Sentence Tokenization >> Word Tokenization >> Graphics
Originally, I had been using observe() statements with reactiveValues() so at each step, I stored off the results into a reactiveValues(). This enabled the save file upload to work like:
Upload Save File >> Set sentences >> Set words >> Graphics
I would like to be able to accomplish something similar but using reactive() statements. So, given that I have uploadedFiles = reactive() and uploadedSave = reactive() how do I write a reactive with the following pseudo code:
rawText = reactive({
if uploadedFiles() flushes reactivity then uploadedFiles()
else if uploadedSave() flushes reactivity then uploadedSave()
else NULL
})
I don't have an "error" I'm trying to troubleshoot, just trying to think through the process of using a reactive to act like a 'most recently flushed' gate to allow my data flow to start from two different places and converge to a single one.
I'm going to show how I do it, but I have a feeling it is not a great method. I'm interested in hearing what the best method is and what's wrong with mine.
new_react <- reactiveValues()
new_react$FilesReact <- 0
new_react$SaveReact <- 0
invalidate <- function(x) x <- x+1
uploadedSave <- eventReactive(new_react$SaveReact,{
# Set sentences >> Set words >> Graphics
})
uploadedFiles <- eventReactive(new_react$FilesReact,{
# Select Sheets >> Select Columns >> Sentence Tokenization >> Word Tokenization >> Graphics
})
## I don't know how you are going to determine whether it's a data file
# or a save file...
if (its_a_save_file) {
new_react$SaveReact <- invalidate(new_react$SaveReact)
uploadedSave()
}else if (its_a_data_file) {
new_react$FilesReact <- invalidate(new_react$FilesReact)
uploadedFiles()
So basically I just define two reactive values which when invalidated by that simple function, will allow for the reactive functions, uploadedSave() or uploadedFiles() to be called.
Edit: To me, this just looks like a way to force eventReactive() to work like observeEvent()
Without more code, it is hard to be specific. Here is an app. that displays a different value based on what is the last control used. The controls are monitored using observeEvent() and each will put its input into a reactive value. Then the output just works with whatever is in the reactive value. For your case you need to have an observeEvent() for each of the controls you are using to do file and save uploads. Then they each put their file into a common reactiveValue and that value is used for further processing.
library(shiny)
app<-shinyApp(
ui=(fluidPage(sliderInput("First", min=1, max=10, label="Slider", value=1),
actionButton("Second", label="Second Button"),
textOutput("OutText"))
),
server=function(input,output){
RV<-reactiveValues(data=NULL)
observeEvent(input$First,
RV$Text<-input$First)
observeEvent(input$Second,
RV$Text<-"Second")
output$OutText<-renderText({
req(RV$Text)
RV$Text
})
}
)
runApp(app)
I'm working on an app in R where the users need to choose a file from their computer, with a RShiny fileInput button. I want to modify this, so that the associated variable can be assigned (i.e. a file can be loaded) automatically by the programm, without having the user click on the button and choose the file.
The problem I'm facing is that a fileInput has 4 fields, amongst which I only can know 3. For instance, when I load the file hello.csv in the variable inFile through the normal procedure, here is what I get :
inFile$name = hello.csv
inFile$size = 8320
inFile$type = text/csv
inFile$datapath = C:\\Users\\MyName\\AppData\\Local\\Temp\\Rtmpkh8Zcb/7d5f0ff0111d440c7a66b656/0
Though I could have guessed the second and the third one knowing the file, I have no idea how the datapath field is assigned...
I've tried to declare inFile as a NULL global variable, then to assign one by one the different fields, but I'm stuck with this last one. Is there an other way to do, like a function that mimics the behaviour of a user who clicks on the file input button and choose a specified file ?
Thank you very much.
If all you're looking to do is load a file initially, you don't have to rely on Shiny functions to do that. You can just rely on R functions. Set up your app like this:
ui <- shinyUI(
fileInput("inFile", label="Choose a file", multiple=F)
)
server <- shinyServer(function(input, output, session) {
values <- reactiveValues()
dat <- reactive({
if (is.null(inFile$datapath)) {
dat <- read.csv("path/to/your.csv")
values$file_name = "your.csv"
values$file_type = "csv"
values$file_size = file.size("path/to/your.csv")
values$file_path = "path/to/your.csv"
} else {
dat <- read.csv(inFile$datapath)
values$file_name = inFile$name
values$file_size = inFile$size
values$file_type = inFile$type
values$file_path = inFile$datapath
}
})
})
shinyApp(ui=ui, server=server)
In the above code, the Shiny app will start and see that inFile$datapath is NULL and will load a predefined file of your choosing. It won't run again until inFile changes, at which point it will load the file that the user pointed to.
Hope that helps.
Update
I changed the code above to use reactiveValues to store the pieces of information that need to be used throughout the app. If you just set those and then do a find/replace for input$inFile$datapath and replace it values$file_path, your code should work just fine.
Here is how I figured it out :
I edited the original code, so that all the read.csv(...) are replaced with calls to a data.frame global variable. I also added a small button that you need to click on before you continue. This button saves what you just loaded in the Database (if you chose a file with the fileInput) and assigns the right values to the global variables that will be needed for the following operations. If you chose no file at all, it will directly assign the variables from the data found in the Database.
So I did not find a proper solution to the problem, but this is a workaround that will do the job in my case.
#brittenb I couldn't get your reactive solution to work as I wanted to, that's why I ended up doing this another way. Thanks for having taken the time to think about it though.
I'm still open to suggestions on how to update the file in a fileInput without user interaction.
I am stuck in a small problem related to shiny/R.
I am reading in a text file and displaying selective column names returned by grep search into the shiny application on the fly. For this, I am using the dynamicUI.
After the file is read in, the following function runs in server.R. It checks for specific colnames and displays this on the UI using uiOutput. Whatever column names are selected by the user, they are sent to another function for data processing and the plot it returned on the mainPanel.
server.R
output$Bait <- renderUI({
data <- input.data();
if(is.null(data)) return()
colnames <- names(data)
colnames = colnames[grep("*LFQ*",colnames,ignore.case=TRUE)]
# Creating the checkboxes using the above colnames
checkboxGroupInput("bait", "Choose Bait LFQ columns",
choices = colnames,
selected = colnames)
})
ui.R
shinyUI(
sidebarPanel(
uiOutput("Bait"),
),
mainPanel(
plotOutput(outputId = 'plot'),
)
)
Everything is fine, what I am trying to create is an action button for the checkboxes. Some files are big and have a longer list of column names >60, so whenever a checkbox is clicked, the whole function runs for processing and displays a plot. This gets unnecessary when the user has to deselect/select more than 10 columns.
An easy fix is, I kept selected=NULL but what I want is to add an actionButton after the checkboxGroupInput, so that user can select as many as checkBoxes but the function only runs when the GO button is pressed via the actionButton. If add a actionButton control after the checkbocGroupInput, it doesnt' works.
Can someone guide me in this regard. After working on this for sometime, now I am bit lost.
Thanks
Did you look into ?isolate? Lets say i want function initialFunction() only be evaluated if input$actionButtonis clicked.
observe({
input$actionButton # everything that triggers initialFunction() should come before isolate()
isolate({
# everything that should not trigger initialFunction() should come inside isolate()
initialFunction()
})
})
I am new to R and I am creating a shiny application to read a csv and filter data. I am reading the csv file, then creating dropdowns with a loop using the column names and the unique values:
output$dropdowns <- renderUI({
if (is.null(x())) {
return(NULL)
}
lapply(1:ncol(x()), function(i) {
selectInput(names(x()[i]), names(x()[i]), c("ALL", unique(as.character(x()[,i]))))
})
I am now trying to filter the data based on the input from the user. To get the input I am trying to loop through the names (names(x)[i]), which is the ID of the selectinput and get the value. But whenever I use input$names(x)[i], I get the following error:
Error: attempt to apply non-function.
I have tried to test this using an actual header (e.g. input$testHeader) and this works fine. But when I try to do the same with a variable, e.g.:
a < - "testHeader"
print(input$a).
This returns NULL. I assume it is looking for a selecinput with ID "a" and cannot find it. But I have no idead how else to try?
Any help would be great.
Thanks.
input is just a reactivevalues object so you can use [[:
print(input[[a]])
I have built a shiny application which is located at the URL below.
https://hdoran.shinyapps.io/openAnalysis/
On the tab called "Choose CrossFit Open Data" I have a textInput() function that calls a function that uses grep(), which is used to find names in a data frame.
The first time the program loads and a name is entered, the search seemingly occurs quickly and names are returned. However, when I delete the name and type a second name, the search is seemingly very slow.
Is there something I can do to optimize this so that is performs quickly always?
I'm still quite new at shiny and am not sure if somehow making this a reactive expression would help. If so, I'm not quite sure how.
Thanks in advance.
The relevant portion of code in the ui.R file
textInput("name", label = 'Enter an athlete name and find your scores',
value = "Enter Name Here")
and the relevant portion of code in the server.R file is
output$myScores <- renderPrint({
df <- filedata()
df[grep(input$name, df$Competitor),]
})
And this portion is also in the ui.R file (though I'm not sure it is relevant to the problem)
verbatimTextOutput("myScores"),
If I understand your goal correctly, you want to give the user the ability to select an input variable based on searching a the competitor column of the dataframe called by filedata()? If so, selectizeInput() is what you are looking for, using server-side selection as outlined here.
Adapted to the code you provided:
ui.r
selectizeInput("name", choices = NULL, multiple = FALSE)
server.r
updateSelectizeInput(session, "name", choices = filedata()$competitor, server = TRUE)
output$myScores <- renderPrint({
df <- filedata()
subset(df, competitor==input$name)
})