Trouble getting user input to pass into function in shiny

Hello!

I am trying to pass user text into a function. The premise is to have a user type in the title ID (tt) of an IMDb listing. This will then pass into a function that will render a tree diagram. I am just running into an issue and I don't know if it is tasking 'too much'?

I am still wet behind the ears when it comes to shiny.

I have set the placeholder text for the input box to be the IMDb listing for good omens, so upon running it should start the function.

Here is the reprex:

library(rvest)
#> Loading required package: xml2
library(shiny)
library(stringr)
library(purrr)
#> 
#> Attaching package: 'purrr'
#> The following object is masked from 'package:rvest':
#> 
#>     pluck
library(collapsibleTree)
library(htmlwidgets)
library(dplyr)
#> 
#> 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
library(stringr)


ui <- fluidPage(
    titlePanel("IMDb: More Like This",windowTitle = "RMDb"),
    sidebarLayout(
        sidebarPanel(
            textInput("tt", "Show Title ID", "tt1869454"),
            br(),
        ),
        mainPanel(
            verbatimTextOutput("nText"),
            plotOutput("scatter")
        ),
        position = c("left","right")
    )
)
server <- function(input, output){
    # Create function for text to render
    output$nText <- renderUI({ 
    # Add below
        url <- paste0("https://www.imdb.com/title/",input$tt,"/")
        # Show Name for later
       show_name <-  url %>% 
            read_html() %>% 
            html_nodes("h1") %>%
            html_text()
       # This extracts the titles of the shows that are similar to the one you searched.
       show_tree_show <- url %>% 
           read_html() %>% 
           html_nodes(".rec-title b") %>% 
           html_text(trim=T)
       # This extracts the tt from the shows saved in the previous step
       show_morelike <- url %>% 
           read_html() %>% 
           html_nodes(".rec_item,.rec_selected") %>% 
           html_attr("data-tconst") 
       # This makes a vector of all (12) of the URLs
       urls <- paste0("https://www.imdb.com/title/",show_morelike,"/")
       # Since we are working with 12 URLs we need to use the map function to apply this function over a list. 
       doThis <- function(i){
           show_tree <- read_html(i) %>% 
               html_nodes(".rec-title b") %>% 
               html_text(trim=T)
       }
       # This runs the function with each URL in the vector
       shows_tree_like_chr <- unlist(map(urls,doThis))
       # This sets up the data how we need it by repeating each show title 12 times
       show_tree_showlist <- NULL
       for (i in 1:12){
           show_tree_showlist <- rep(show_tree_show,each=12)
       }
       # The name of the dataframe should be changed to reflect the show you are working with. 
       show_tree <- data.frame(
           show=show_tree_showlist,
           shows_like_shows=shows_tree_like_chr
       )
       head(show_tree)
    # End function
        })
}

shinyApp(ui, server)
#> 
#> Listening on http://127.0.0.1:7793
#> Warning: Error in if: argument is of length zero

Created on 2020-07-31 by the reprex package (v0.3.0)

The major issue you encountered relates to the shiny ui widget choice and accompanying renderfunction.
The nText function code is set to return a dataframe, so a tableOutput should be the UI to show such a thing, this will require the renderTable servercode wrapper.
Additionally, it seems quite slow to poll the URL's to compile the data. so I added spinners from shinycssloaders, as well as the built in shiny progress bar feature.
Note that the scatter content hasnt been defined so that spinner wont stop spinning.
Hope this helps.

library(rvest)
 
library(shiny)
library(stringr)
library(purrr)
 
library(collapsibleTree)
library(htmlwidgets)
library(dplyr)
 
library(shinycssloaders)


ui <- fluidPage(
  titlePanel("IMDb: More Like This",windowTitle = "RMDb"),
  sidebarLayout(
    sidebarPanel(
      textInput("tt", "Show Title ID", "tt1869454"),
      br(),
    ),
    mainPanel(
      tableOutput("nText") %>% withSpinner(),
      plotOutput("scatter")  %>% withSpinner()
    ),
    position = c("left","right")
  )
)
server <- function(input, output){
  # Create function for text to render
  output$nText <- renderTable({ 
    withProgress(message = 'Fetching URLS ', value = 0, {
    # Add below
    url <- paste0("https://www.imdb.com/title/",input$tt,"/")
    myhtml <- url %>% 
      read_html()
    
    incProgress(amount=1/13)
    # Show Name for later
    show_name <-  myhtml %>% 
      html_nodes("h1") %>%
      html_text()
    # This extracts the titles of the shows that are similar to the one you searched.
    show_tree_show <-myhtml %>% 
      html_nodes(".rec-title b") %>% 
      html_text(trim=T)
    # This extracts the tt from the shows saved in the previous step
    show_morelike <-myhtml %>% 
      html_nodes(".rec_item,.rec_selected") %>% 
      html_attr("data-tconst") 
    # This makes a vector of all (12) of the URLs
    urls <- paste0("https://www.imdb.com/title/",show_morelike,"/")
    # Since we are working with 12 URLs we need to use the map function to apply this function over a list. 
    doThis <- function(i){
      show_tree <- read_html(i) %>% 
        html_nodes(".rec-title b") %>% 
        html_text(trim=T)
      incProgress(amount=1/13)
      show_tree
    }
    # This runs the function with each URL in the vector
    shows_tree_like_chr <- unlist(map(urls,doThis))
    # This sets up the data how we need it by repeating each show title 12 times
    show_tree_showlist <- NULL
    for (i in 1:12){
      show_tree_showlist <- rep(show_tree_show,each=12)
    }
    # The name of the dataframe should be changed to reflect the show you are working with. 
    show_tree <- data.frame(
      show=show_tree_showlist,
      shows_like_shows=shows_tree_like_chr
    )

    })
    head(show_tree)
    # End function
  })
}

shinyApp(ui, server)

EDIT: So after deciding to play around with it for a bit, I realized that you already explained the answer! If I am correct, because the desired output was outputTable, everything could just be grouped under that output.

So for my purpose, I put all of that under renderCollapsibleTree and now it seems to be working! Thank you so much, I am beyond words!


Old post below

Wow, this is so awesome!

Thank you for taking the time to take a look at this. I am so glad that you added the loaders because I know that the user would not want to see "HTTP 404"!

So this gets the table rendered perfectly! But I am having a difficult time of getting this dataframe to be global enough that it can pass into the plotOutput() function. For my example I would like to be able to pass the tree dataframe into a renderCollapsibleTree function but it returns the following error: "Error: Object 'tree' not found"

Here is the code I've added in the ui:

   collapsibleTreeOutput("tree")  %>% withSpinner()

And here is the code I've added in the server, beneath the renderTable call:

    output$tree <- renderCollapsibleTree({
        collapsibleTree(
            tree,
            hierarchy=c("show","shows_like_shows"),
            root=paste0(show_name)
            )
    })

Thank you again for your help!

Hi Dave, you must be close but tree isnt an object whose definition you've provide me yet. is it intended to be the show_tree object, or are there difference ?

Hello! I think I've used show_tree or tree before, but this is just a dataframe of the list of similar shows, show_tree_show and their similar shows show_morelike. I know my naming conventions are not the best!

What you've given me works perfectly now! I added a new function that would hopefully make it easier for the user to just type in a show title. But the progress bar keeps spinning, but only if I run the app in a window.

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.