Putting together a shiny app

I am building a shiny app. The directory name is "nextword-app"The app is supposed to read in a four word phrase, look it up to see if it is in a dictionary, and return the most likely word that follows the phrase. I've already written a function called whatsnexta that predicts the fifth word after a four word phrase is typed in. This function I put in the helpers.R file which is in the "nextword-app" directory. The dictionary "dictionary.rds" is in a data folder in the directory. I think all the files are in the right place and the problem is in the app.R, most likely in the server function. Here is my app.R

# Load packages ----

library(dplyr)
library(stringr)

# Load data ----

source("nextword-app/helpers.R")
dat <- readRDS("nextword-app/data/dictionary.rds")




library(shiny)
ui <- fluidPage(headerPanel("What Will They Say Next?"),
                textInput(inputId="predictor_words", label = "type in four words"),
                textOutput(outputId="predicted_word")
)

server <- function(input, output){
  output$predicted_word <- renderText({
    data <-dictionary.rds
    whatsnexta(phrase=input$predictor_words)})
  
}

shinyApp (ui=ui, server=server)

The error message I get is here:

Attaching package: ‘dplyr’

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union

Warning in file(filename, "r", encoding = encoding) :
  cannot open file 'nextword-app/helpers.R': No such file or directory
Error in file(filename, "r", encoding = encoding) : 
  cannot open the connection

You are already in the "nextword-app" folder, you shouldn't include it in your file paths, try with

source("helpers.R")
dat <- readRDS("data/dictionary.rds")

I made the correction. Here's the app.R now.

library(dplyr)
library(stringr)

# Load data ----


source("helpers.R")
dat <- readRDS("data/dictionary.rds")


library(shiny)
ui <- fluidPage(headerPanel("What Will They Say Next?"),
                textInput(inputId="predictor_words", label = "type in four words"),
                textOutput(outputId="predicted_word")
)

server <- function(input, output){
  output$predicted_word <- renderText({
    data <-dictionary.rds
    whatsnexta(phrase=input$predictor_words)})
  
}

shinyApp (ui=ui, server=server)

A new error message says:

Loading required package: shiny
Warning: package ‘shiny’ was built under R version 3.6.1

Attaching package: ‘dplyr’

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union

Warning in gzfile(file, "rb") :
  cannot open compressed file 'dictionary.rds', probable reason 'No such file or directory'
Error in gzfile(file, "rb") : cannot open the connection

This suggests that dictionary.rds file is not located on this path data/dictionary.rds, are you sure this file is located at that folder?

On the explorer file on my computer, I see a filepath
This PC > Documents > nextword-app > data > dictionary

Just to be sure, what is the output of runing list.files(path = "path_to_nextword-app",recursive = TRUE)? (but using the actual path to your "nextword-app" folder)

list.files("C:/Users/mlrob/OneDrive/Documents", recursive=TRUE)

after a few seconds, I get a very long list of all the files in the path.
[293] "nextword-app/app.R"
[294] "nextword-app/data/dictionary.rds"
[295] "nextword-app/helpers.R"
...
are on the list of the many entries.
[1000] "R/win-library/3.4/BH/include/boost/asio/detail/std_thread.hpp"
[ reached getOption("max.print") -- omitted 59333 entries ]

First, I commented out a load data statement in my helpers.R file. The helpers.R file now looks like this

#dat<- readRDS("dictionary.rds")
#function that outputs the next word after a phrase is typed in 
library(stringr) 
library(dplyr)
nxtword1<- function(word){dat %>% filter(word1 == word) %>% select(-word1)}
##function to change ngram to n-1 gram
less1gram <- function(x){str_replace(x, "^[^ ]+ ", "")
} 

# To print out the most common unigrams instead of a row of NAs,
##should no match be found
whatsnexta <- function(phrase) {
  nwords <-str_count(phrase, pattern=" ")
  while (!(phrase %in% dat$word1)  && nwords >=1){
    phrase<- less1gram(phrase)
    nwords<-str_count(phrase, pattern=" ")
    
    #if (!(phrase %in% dat$word1)  && nwords>0) 
    
    #{ print(nxtword1(phrase)[1:5, 1])}
    if ((phrase %in% dat$word1)   ){
      print(nxtword1(phrase)[1:5, 1])
    }
    if (!(phrase %in% dat$word1)  && nwords==0) 
    { print(c("the","to", "and", "in", "of"))}
  }
}

Next, I reran the app. It seemed to go further than previously, even showed an app, that had an error message on it. The message on the console

> runApp('nextword-app')

Listening on http://127.0.0.1:7644
Warning: Error in renderText: object 'dictionary.rds' not found
  96: renderText [C:\Users\mlrob\OneDrive\Documents\nextword-app/app.R#21]
  95: func
  82: origRenderFunc
  81: output$predicted_word
   1: runApp

That error is because this is not a valid R command, you already have read dictionary.rds as dat so use that instead.

1 Like

Here is my app.R code now.

# Load packages ----

library(dplyr)
library(stringr)

# Load packages ----

library(dplyr)
library(stringr)

# Load data ----


source("helpers.R")
dat <- readRDS("data/dictionary.rds")
library(stringr) 
library(dplyr)



library(shiny)
ui <- fluidPage(headerPanel("What Will They Say Next?"),
                textInput(inputId="predictor_words", label = "type in four words"),
                textOutput(outputId="predicted_word")
)

server <- function(input, output){
  output$predicted_word <- renderText({
    #dat <-dictionary.rds
    phrase <- textInput$predictor_words
    whatsnexta(phrase=input$predictor_words)})
  
}

shinyApp (ui=ui, server=server)

The app will be there, but there is another error message:

> shiny::runApp('nextword-app')
 runApp('nextword-app')

Listening on http://127.0.0.1:4886
Warning: Error in $: object of type 'closure' is not subsettable
  96: renderText [C:\Users\mlrob\OneDrive\Documents\nextword-app/app.R#25]
  95: func
  82: origRenderFunc
  81: output$predicted_word
   1: runApp

I re-ran the function whatsnexta, which is in my helpers.R file. It was working.

Hi @Quack!

Whenever you see "object of type 'closure' is not subsettable", it's a good idea to first check for a syntax error or typo somewhere. A "closure" is R's word for a function, so R is saying that you tried to subset a function using $ (which you almost certainly did not intend to do!).

In this case, the error message is also telling us that the problem is in the renderText() function that's being supplied as the definition for output$predicted_word. What jumps out to me in that block of code is:

phrase <- textInput$predictor_words

I think you meant to type input$predictor_words there?

You also don't seem to be actually using the phrase variable that you defined in that line. Two ways of fixing that:

output$predicted_word <- renderText({
    phrase <- input$predictor_words
    whatsnexta(phrase = phrase)
})

or

output$predicted_word <- renderText({
    whatsnexta(phrase = input$predictor_words)
})
1 Like
# Load packages ----

library(dplyr)
library(stringr)

# Load data ----


source("helpers.R")
dat <- readRDS("data/dictionary.rds")
library(stringr) 
library(dplyr)
library(shiny)
ui <- fluidPage(headerPanel("What Will They Say Next?"),
                textInput(inputId="predictor_words", label = "type in four words"),
                textOutput(outputId="predicted_word")
)

server <- function(input, output){
  output$predicted_word <- renderText({
    whatsnexta(phrase = input$predictor_words)
    paste("the next word is", output$predicted_word)
  })
  
}
shinyApp (ui=ui, server=server)

My output was showing in the console window. I've been trying to get the output to show in the Shiny window, in the main panel. I will get this error message

Listening on http://127.0.0.1:4842
Warning: Error in $.shinyoutput: Reading objects from shinyoutput object not allowed.
  100: stop
   99: $.shinyoutput
   96: renderText [C:\Users\mlrob\OneDrive\Documents\nextword-app/app.R#22]
   95: func
   82: origRenderFunc
   81: output$predicted_word
    1: runApp

That error message is because you can't do this, it's recursive and makes no sense, maybe you where trying to do this instead

  output$predicted_word <- renderText({
    paste("the next word is", whatsnexta(phrase = input$predictor_words))
  })

But I suspect the problem is that your whatsnexta() function doesn't return any value but prints the result to the console.

Yes, your suspicion is correct.
The whatsnexta() function prints the result to the console. If I try to save the result to an object with

> whatsnext<- whatsnexta("and a case of")
[1] "one" NA    NA    NA    NA   

the result is returned to the console. When I check the Global Environment window, whatsnext is said to be NULL (empty). Is there a remedy for this?

Yes, check your function and make sure that it works as intended, I can't give you any specific advice about this since I can't test your function (you have not provided a REPRoducible EXample (reprex) or sample data).

A repex

#Created a dictionary of unigrams, bigrams, trigrams.

dat<- data.frame(word1=c(  "will", "like","get", "look", "next", "social",  
                "cinco_de","manufacturer_custom", "custom_built"), word2=c(" ", " ", " ", 
"like","week", "media", "mayo", "built", "painted"), frequency = c( 5153, 5081, 4821,  
559, 478,465, 172,171,171 ) )
dat

  

#Here is a function to look up words in the dictionary (named dat)
        # write a function that returns the second word when the prefix is typed in.

library(dplyr)
library(stringr)

whatsnext5 <- function(phrase) {
  nwords <-str_count(phrase, pattern=" ")
  ##The number of words in the prefix is nwords +1
  ##If there is no match in the dat the next smaller ngram will be looked up.  This continues until a 
  ##match is found.  Then the matching words will be outputted.
  while (!(phrase %in% dat$word1)  && nwords >=1){
    #phrase<- less1gram(phrase)
    phrase <-str_replace(phrase, "^[^ ]+ ", "")
    nwords<-str_count(phrase, pattern=" ")
    
    ##Match found
    if ((phrase %in% dat$word1)   ){
     
      answer <-dat %>% filter(word1 == phrase) %>% select(-word1)
      print(answer[1:5, 1])
    }
    ##Match not found
    if (!(phrase %in% dat$word1)  && nwords==0) 
      #Here no match was found, so the five most common unigrams are outputted.
    { print(c("the","to", "and", "in", "of"))}
  }
}
      
 whatsnext5("manufacturer_custom")      
Nothing happened here--no error message, just nothing.

This seems like an assignment to me so I'm not going to fix your function for you, but I can give you a hint, the logical condition in the while() statement returns FALSE, so the code inside the loop never gets executed.

library(stringr)

dat<- data.frame(word1=c(  "will", "like","get", "look", "next", "social",  
                           "cinco_de","manufacturer_custom", "custom_built"),
                 word2=c(" ", " ", " ", "like","week", "media", "mayo", "built", "painted"),
                 frequency = c( 5153, 5081, 4821, 559, 478,465, 172,171,171 ))

phrase = "manufacturer_custom"
nwords <- str_count(phrase, pattern=" ")
nwords
#> [1] 0
!(phrase %in% dat$word1) && nwords >=1
#> [1] FALSE

Created on 2019-08-26 by the reprex package (v0.3.0.9000)

I think I fixed the troubles in my code. They had to do with underscores used in the past instead of blank spaces.

######Make a repex
dat<- data.frame(word1=c(  "will", "like","get", "look", "next", "social",  
                           "cinco de","manufacturer custom", "custom built"), word2=c(" ", " ", " ", 
                                                                                      "like","week", "media", "mayo", "built", "painted"), frequency = c( 5153, 5081, 4821,  
                                                                                                                                                          559, 478,465, 172,171,171 ) )
dat

#Attempt while loop
#Use while loop
whatsnext <- function(phrase){
nwords <-str_count(phrase, pattern=" ")
while (!(phrase %in% dat$word1) & nwords >=1){

#phrase<- less1gram(phrase)
  phrase <-str_replace(phrase, "^[^ ]+ ", "")
#print(phrase)
nwords<-str_count(phrase, pattern=" ")
#print(nxtword1(phrase))
answer <-dat %>% filter(word1 == phrase) %>% select(-word1)
print(answer[1:5, 1])
}
}

The console printed this

> whatsnext("It was a custom built")
[1] <NA> <NA> <NA> <NA> <NA>
Levels:   built like mayo media painted week
[1] <NA> <NA> <NA> <NA> <NA>
Levels:   built like mayo media painted week
[1] painted <NA>    <NA>    <NA>    <NA>   
Levels:   built like mayo media painted week
> 

Why did R print out three times? What do Levels: indicate?
How can I get answer[1:5, 1] ? I wanted it to show up in the Shiny window as text..

Because you are using a while loop and it is going to print an answer for each iteration, this is how you have designed your code, if this is not what you want, check your logic again.

The word2 column (the one you are subseting with answer[1:5, 1]) is a factor variable and levels are the unique values in that variable.

Sorry but answering that would be the same as doing your work for you and that would go against our homework policy

I fixed my helpers.R and I got answer[1:5, 1] Here is my code

#function that outputs the next word after a phrase is typed in 
library(stringr) 
library(dplyr)
#nxtword1<- function(word){dat %>% filter(word1 == word) %>% select(-word1)}
##function to change ngram to n-1 gram
#less1gram <- function(x){str_replace(x, "^[^ ]+ ", "")
#} 

# To print out the most common unigrams instead of a row of NAs,
##should no match be found.  The number of words in the prefix is nwords + 1
whatsnexta <- function(phrase) {
  nwords <-str_count(phrase, pattern=" ")
  ##While loop works when no matches are found in tge dictionary and there is more than one word in
  #the prefix
  while (!(phrase %in% dat$word1)  && nwords >=1){
    #phrase<- less1gram(phrase)
    phrase <-str_replace(phrase, "^[^ ]+ ", "")
    nwords<-str_count(phrase, pattern=" ")
    
    # A match is found 
    
    #{ print(nxtword1(phrase)[1:5, 1])}Output the next word
    if ((phrase %in% dat$word1)   ){
      # print(nxtword1(phrase)[1:5, 1])
      answer <-dat %>% filter(word1 == phrase) %>% select(-word1)
      # print(answer[1:5, 1])
      #print(answer)
    }
    #No match found.  Output the five most common unigrams
    if (!(phrase %in% dat$word1)  && nwords==0) 
    { answer <-(c("the","to", "and", "in", "of"))}
  }
  answer5 <- answer[1:5, 1]
  
}

I tried to put answer5 on Shiny. Shiny posted this error message

> shiny::runApp('nextword-app')
Loading required package: shiny
Warning: package ‘shiny’ was built under R version 3.6.1

Listening on http://127.0.0.1:3281
Warning: Error in whatsnexta: object 'answer' not found
  98: whatsnexta [helpers.R#33]
  96: renderText [C:\Users\mlrob\OneDrive\Documents\nextword-app/app.R#21]
  95: func
  82: origRenderFunc
  81: output$predicted_word
   1: shiny::runApp

What can I do to get Shiny to print out answer5 ?