for-loopshinywordcloud2

For Loop in Shiny Server: How to Not Overwrite Values with Each ActionButton Press?


I am trying to create an app in which part of the UI displays a wordcloud generated by words/strings inputted by the user. To do this, I pass the input to a for loop which is supposed to then store every input in an empty vector with ever press of the action button. However, I am encountering a couple problems, though: one in that no word cloud is displaying, with no error indicated, and another in that the for loop will just overwrite the vector each time the button is pressed, such that it always only has one word in it instead of gradually adding more words. I figured the lack of display is because there is only one word, and it seems like wordcloud needs at least two words to print anything: so how can I get the for loop to work as intended with Shiny?

library(shiny)
library(stringr)
library(stringi)
library(wordcloud2)



ui <- fluidPage(

titlePanel("Strings Sim"),

 sidebarLayout(
 sidebarPanel(
  textInput("string.input", "Create a string:", placeholder = "string <-"),
  actionButton("go1", "GO!")
),

  mainPanel(
   textOutput("dummy"),
   wordcloud2Output("the.cloud")
  )


)
)

server <- function(input, output, session) {


 observeEvent(input$go1, {

   high.strung <- as.vector(input$string.input)
   empty.words <- NULL

for (i in high.strung) {
  empty.words <- c(empty.words, i)
}

word.vector <-matrix(empty.words, nrow = length(empty.words),ncol=1)

num.vector <- matrix(sample(1000), nrow=length(empty.words),ncol=1)

prelim <- cbind(word.vector, num.vector)

prelim.data <- as.data.frame(prelim)

prelim.data$V2 <- as.numeric(as.character(prelim.data$V2))

 output$the.cloud <- renderWordcloud2(
  wordcloud2(prelim.data)
   )

print(empty.words)
  })
  }

     shinyApp(ui=ui,server=server)

The operation works as intended when I run it without Shiny code; I basically just use a string in place of the input, run through the for loop a few times to generate the dataframe to be used by word cloud, and get something like the attached picture, which is what I am after:Example Output

Functional code without Shiny:

 empty.words <- NULL

 #Rerun below here to populate vector with more words and regenerate wordcloud

 high.strung <- as.vector("gumbo")

 for (i in high.strung) {
   empty.words <- c(empty.words, i)
   return(empty.words)
 }

 word.vector <-matrix(empty.words, nrow = length(empty.words),ncol=1)

 num.vector <- matrix(sample(1000), nrow=length(empty.words),ncol=1)

 prelim <- cbind(word.vector, num.vector)

 prelim.data <- as.data.frame(prelim)

 prelim.data$V2 <- as.numeric(as.character(prelim.data$V2))

 str(prelim.data)

 wordcloud2(prelim.data)

Any help is much appreciated!

Edit: More pictures of the desired output using the non-Shiny code. (I editted the dataframe output to overlay the wordcloud just to show the cloud and frame in one picture, i.e. don't need them to display in that way). With each press of the button, the inputted word(s) should be added to the dataframe that builds the cloud, gradually making it larger.The random number vector which determines the size doesn't have to stay the same with each press, but each inputted word should be preserved in a vector. Ex2 Ex3


Solution

  • Your app is missing reactivity. You can read about that concept here. You can input strings and as soon as at least two words are in the dataframe the wordcloud is rendered. If you don't want multi-word strings to be split just take out the str_split() function.

    library(shiny)
    library(stringr)
    library(stringi)
    library(wordcloud2)
    
    
    
    ui <- fluidPage(
    
      titlePanel("Strings Sim"),
    
      sidebarLayout(
        sidebarPanel(
          textInput("string.input", "Create a string:", placeholder = "string <-"),
          actionButton("go1", "GO!")
        ),
    
        mainPanel(
          textOutput("dummy"),
          wordcloud2Output("the.cloud")
        )
    
    
      )
    )
    
    server <- function(input, output, session) {
    
      rv <- reactiveValues(high.strung = NULL)
      observeEvent(input$go1, {
        rv$high.strung <- c(rv$high.strung,str_split(c(input$string.input), pattern = " ") %>% unlist)
      })
    
      prelim.data <- reactive({
        prelim <- data.frame(
          word.vector = rv$high.strung, 
          num.vector = sample(1000, length(rv$high.strung), replace = TRUE)
        )
      })
    
      output$the.cloud <- renderWordcloud2(
        if (length(rv$high.strung) > 0)
          wordcloud2(prelim.data())
      )
    
    }
    
    shinyApp(ui=ui,server=server)