I'm working on a some text mining. Based on the user's input I'm generating a number of suggestions for the next word. This part works fine. However the number of suggestions can be very large, so I want to show at most 10 suggestions in Shiny and I don't want to show NA values.
I created a reproducable example to exhibits the same problem. The trick I'm trying to use is pasting "suggestions" with i. This works when my output does not depend on my input. I got this from http://shiny.rstudio.com/gallery/creating-a-ui-from-a-loop.html.
My ui.R file
library(shiny)
fluidPage(
titlePanel("Test"),
fluidRow(
textAreaInput("userText", label="Enter your text")
),
fluidRow(
lapply(1:5, function(i) {
textOutput(paste0("suggestions", i))})
)
)
My server.R
library(shiny)
mySuggestions <- c("this", "is", "a", "test", "of", "getting", "reactive", "list", "length")
function(input, output, session) {
getWords <- function(i, wrds) {
output[[paste0("suggestions", i)]] <- renderText({ wrds()[i] })
}
userText <- reactive({
# Leaves this function when input$userText is NULL or ""
req(input$userText)
input$userText })
words <- reactive({
mySuggestions[1:userText()]
})
# Problem
lapply(reactive({ 1:min(5, length(words())) }), getWords(), wrds=words())
}
When you enter a positive integer in the ui text field the app is supposed to show as many words, but 5 at most.
The above version of the server.R results in a warning "Warning: Error in paste0: argument "i" is missing, with no default" I've tried several versions for this problematic line.
reactive({ lapply(1:min(5, length(words())), getWords(), wrds=words() ) })
Gives no errors, but it shows nothing in the output.
lapply(1:min(5, length(words())), getWords() , wrds=words())
Results in a warning "Warning: Error in paste0: argument "i" is missing, with no default"
lapply(reactive({1:min(5, length(words()))}), getWords(), wrds=words())
Results in a warning "Warning: Error in paste0: argument "i" is missing, with no default"
lapply(reactive({1:min(5, length(words))}), function(i) {
output[[paste0("suggestions", i)]] <- renderText({ words[i] }) } )
Results in Error in as.vector(x, "list") : cannot coerce type 'closure' to vector of type 'list'
lapply(reactive({1:min(5, length(words()))}), function(i) {
output[[paste0("suggestions", i)]] <- renderText({ words()[i] }) } )
Results in Error in as.vector(x, "list") : cannot coerce type 'closure' to vector of type 'list'
reactive({lapply(1:min(5, length(words)), function(i) {
output[[paste0("suggestions", i)]] <- renderText({ words[i] }) }) })
Gives no errors, but it shows nothing in the output.
reactive({lapply(1:min(5, length(words())), function(i) {
output[[paste0("suggestions", i)]] <- renderText({ words()[i] }) }) })
Gives no errors, but it shows nothing in the output.
lapply(1:min(5, reactive({ length(words )})), function(i) {
output[[paste0("suggestions", i)]] <- renderText({ words[i] }) })
Results in Error in min(5, reactive({ : invalid 'type' (closure) of argument
lapply(1:min(5, reactive({ length(words() )})), function(i) {
output[[paste0("suggestions", i)]] <- renderText({ words()[i] }) })
Results in Error in min(5, reactive({ : invalid 'type' (closure) of argument
Now the following line shows the entered number of words in a single text field. When I enter 2 it shows 2 words and when I enter 20 it shows 5 words. This is the behaviour I want, but I want each word in a separate text field.
output$suggestions1 <- renderText(words()[1:min(5, length(words()))])
I'm getting lost. I was getting so desperate that I tried a few things I did not expect to work. Is it possible to do what I want? If so, how? If not, what is the problem? I haven't found anything yet that addresses this specific problem.
The combination of outputUI and renderUI works great and keeps the code relatively simple.
ui.R
server.R
I didn't know what outputUI and renderUI did, but they seem perfect for situations like these.