Reactive SelectInput (Dataset Unknown until API call from Previous Filter)

泪湿孤枕 提交于 2019-12-13 03:54:13

问题


I am creating a shiny app that will do the following using Spotify's API:

1) You manually type in the Artist Name

2) In the selectInput, the albums need to automatically populate for your selection.

3) After selecting the album, a table in the main panel will show the songs, artist, and album.

I have this working so far but I cannot figure out how to do the 2nd part which is to automatically populate the albums once the artist is selected. I asked a previous question here: Shiny: Automatic SelectInput Value Update Based on Previous Filter but I realized that after asking the question, the dataset will not be known in the beginning for you to reference in the ui.

So instead of doing this:

selectInput("selectinputid", "Album #1 to Select:", choices = c("Yeezus" = "Yeezus", "Graduation" = "Graduation", "Gears" = "gear"))

I want to do this:

selectInput("selectinputid", "Album #1 to Select:", choices = unique(with_album_name$`Album Name`)

Here is the code:

# ui.R

library(shiny)
shinyUI(fluidPage(
  titlePanel("Spotify: Interactive Song Selection"),
  sidebarLayout(
    sidebarPanel(
      helpText("The goal from this is for you to compare two artists' albums and see how similar the songs are based on the audio features."),

      helpText("Select your first artist you want to compare. For example: ",
           tags$b("Kanye West")),

      textInput("albumId", "Artist Name #1", value = "", width = NULL, 
            placeholder = NULL),

      actionButton("goButton", "Submit Both Artists"),

      helpText("Based on the artist you selected, now select the albums that you want to compare songs for."),

      selectInput("selectinputid", "Album #1 to Select:", choices = c("Yeezus" = "Yeezus", "Graduation" = "Graduation", "Gears" = "gear")),

      actionButton("goButton1", "Submit Both Albums")),

    mainPanel(
      tableOutput("result")
    )
  )
))

Server Section:

# server.R

spotifyKey <- "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
spotifySecret <- "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"

library("httr")
library("jsonlite")
library(ggplot2)
library(scales)
library(dplyr)

response = POST(
  'https://accounts.spotify.com/api/token',
  accept_json(),
  authenticate(spotifyKey, spotifySecret),
  body = list(grant_type = 'client_credentials'),
  encode = 'form',
  verbose()
 )

token = content(response)$access_token

HeaderValue = paste0('Bearer ', token)

library(shiny)
shinyServer(function(input, output) {

  output$result <- renderTable({
    randomVals <- eventReactive(input$goButton, input$albumId)
    spotify <- c(randomVals())

    ##Retrieve Artist ID

    get.artist <- function(spotify){
      artistnameURL <- paste("https://api.spotify.com/v1/search?q=", spotify, "&type=artist", sep="")
      getArtist <- GET(artistnameURL, add_headers(Authorization = HeaderValue))
      artistname <- jsonlite::fromJSON(toJSON(content(getArtist)))
      ids <- data.frame(matrix(unlist(artistname$artists$items$id), 
                           nrow=artistname$artists$total, 
byrow=T),stringsAsFactors=FALSE)
      names <- data.frame(matrix(unlist(artistname$artists$items$name), 
                             nrow=artistname$artists$total, 
byrow=T),stringsAsFactors=FALSE)
      colnames(ids)[1]<-"Artist ID"
      colnames(names)[1]<-"Artist Name"
      artist_search <- cbind(names, ids)
      artist_search <- artist_search[1,]
      return(artist_search)
    }

    df1 <- lapply(spotify, get.artist)
    result2 <- do.call(rbind, df1)
    result2_final<-result2
    ids<-result2_final$`Artist ID`

    ##Retrieve Artist Albums

    get.albums <- function(ids){
      artists_albumsURL <- paste("https://api.spotify.com/v1/artists/", ids, "/albums", sep="")
      getArtistAlbum <- GET(artists_albumsURL, add_headers(Authorization = HeaderValue))
      artistalbumname <- jsonlite::fromJSON(toJSON(content(getArtistAlbum)))
      albumids <- data.frame(matrix(unlist(artistalbumname$items$id), 
                                nrow=artistalbumname$total, 
byrow=T),stringsAsFactors=FALSE)
      albumnames <- data.frame(matrix(unlist(artistalbumname$items$name), 
                                  nrow=artistalbumname$total, 
byrow=T),stringsAsFactors=FALSE)
      artistid2 <- data.frame(matrix(unlist(artistalbumname$items$artists[[1]]$id), 
                                 nrow=artistalbumname$total, 
byrow=T),stringsAsFactors=FALSE)
      artistname2 <- 
data.frame(matrix(unlist(artistalbumname$items$artists[[1]]$name), 
                                   nrow=artistalbumname$total, byrow=T),stringsAsFactors=FALSE)

      colnames(albumids)[1]<-"Album IDs"
      colnames(albumnames)[1]<-"Album Name"
      colnames(artistid2)[1]<-"Artist ID"
      colnames(artistname2[1])<-"Artist Name"
      album_search <- cbind(artistid2, artistname2, albumnames, albumids)
      album_search <- unique(album_search)
      return(album_search)
    }

    df <- lapply(ids, get.albums)

    result <- do.call(rbind, df)
    result_final<-result
    colnames(result_final)[2]<-"Artist Name"
    spotify<-result_final$`Album IDs`

    get.tracks <- function(spotify){
      albumTracksURL <- paste("https://api.spotify.com/v1/albums/", spotify, "/tracks?limit=50", sep="")
      getTracks <- GET(albumTracksURL, add_headers(Authorization = HeaderValue))
      albumTracks <- jsonlite::fromJSON(toJSON(content(getTracks)))

      ids <- data.frame(matrix(unlist(albumTracks$items$id), 
                           nrow=albumTracks$total, byrow=T),stringsAsFactors=FALSE)

      names <- data.frame(matrix(unlist(albumTracks$items$name), 
                             nrow=albumTracks$total, byrow=T),stringsAsFactors=FALSE)
      artists<-albumTracks$items$artists
      artists1<-do.call(rbind, lapply(artists, function(x) do.call(cbind, lapply(x[c('id', 'name')], toString))))

      result <- cbind(ids, names, artists1)

      colnames(result) <- c("ID", "NAME", "ARTIST ID", "ARTIST NAME")
      result$AlbumID <- spotify
      return(result)
    }

    df <- lapply(spotify, get.tracks)

    result <- do.call(rbind, df)
    result_final2<-result

    names(result_final2) <- c("ID", "NAME", "ARTIST ID", "ARTIST NAME")
    final<-result_final2

    final1<-final[!duplicated(final), ]

    final2 <- final1[!duplicated(final1[2:5]),]
    colnames(final2)[5]<-"Album ID"

    with_album_name<-left_join(final2,result_final, by=c("Album ID" = "Album IDs"))
    with_album_name <- with_album_name[,-c(6:7)]

    ##target <- c(input$selectinputid)
    randomVals2 <- eventReactive(input$goButton1, input$selectinputid)
    target <- c(randomVals2())
    result_final<-filter(with_album_name, `Album Name` %in% target)
    final2<-result_final
    final2
   })})

Output:

In the ui part, I need to find a way to reference the with_album_name table, but that table is created in the server section. Not sure how this can be done because right now all I have is to manually put in the album names for selection and that will not work when I want to reference a different artist in the spotify database.


回答1:


I overwrote your server part:

  • moved all functions out of it (I prefer to keep my server function in a separate file);

  • Restructured server code: all code was returning single table. I now added observeEvent to update list

Minor changes in selectInput part:

  selectInput("selectinputid", "Album #1 to Select:", "")

Server part:

server <- function(input, output, session) {
    ids <- reactive({
        randomVals <- eventReactive(input$goButton, input$albumId)
        spotify <- c(randomVals())
        df1 <- lapply(spotify, get.artist)
        result2 <- do.call(rbind, df1)
        result2_final<-result2
        result2_final$`Artist ID`
    })

    result_final <- reactive({
        df <- lapply(ids(), get.albums)
        result <- do.call(rbind, df)
        colnames(result)[2]<-"Artist Name"
        result
    })

   # Observes and updates album selection part
   observe({
        albums <- unique(result_final()$`Album Name`)
        updateSelectInput(session, "selectinputid",
                          label = "selectinputid",
                          choices = albums,
                          selected = albums[1])
    })

    output$result <- renderTable({
        spotify<-result_final()$`Album IDs`
        df <- lapply(spotify, get.tracks)
        result <- do.call(rbind, df)
        result_final2<-result
        names(result_final2) <- c("ID", "NAME", "ARTIST ID", "ARTIST NAME")
        final<-result_final2
        final1<-final[!duplicated(final), ]    
        final2 <- final1[!duplicated(final1[2:5]),]
        colnames(final2)[5]<-"Album ID"    
        with_album_name<-left_join(final2,result_final(), by=c("Album ID" = "Album IDs"))
        with_album_name <- with_album_name[,-c(6:7)] 
        randomVals2 <- eventReactive(input$goButton1, input$selectinputid)
        target <- c(randomVals2())
        result_final<-filter(with_album_name, `Album Name` %in% target)
        final2<-result_final
        final2
    })
}

All code (messy):

library(shiny)
ui <- fluidPage(
  titlePanel("Spotify: Interactive Song Selection"),
  sidebarLayout(
    sidebarPanel(
      helpText("The goal from this is for you to compare two artists' albums and see how similar the songs are based on the audio features."),

      helpText("Select your first artist you want to compare. For example: ",
           tags$b("Kanye West")),

      textInput("albumId", "Artist Name #1", value = "", width = NULL, 
            placeholder = NULL),

      actionButton("goButton", "Submit Both Artists"),

      helpText("Based on the artist you selected, now select the albums that you want to compare songs for."),

       selectInput("selectinputid", "Album #1 to Select:", ""),

      actionButton("goButton1", "Submit Both Albums")),

    mainPanel(
      tableOutput("result")
    )
  )
)


spotifyKey <- "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
spotifySecret <- "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"

library("httr")
library("jsonlite")
library(ggplot2)
library(scales)
library(dplyr)

response = POST(
  'https://accounts.spotify.com/api/token',
  accept_json(),
  authenticate(spotifyKey, spotifySecret),
  body = list(grant_type = 'client_credentials'),
  encode = 'form',
  verbose()
 )

token = content(response)$access_token

HeaderValue = paste0('Bearer ', token)

    get.artist <- function(spotify){
      artistnameURL <- paste("https://api.spotify.com/v1/search?q=", spotify, "&type=artist", sep="")
      getArtist <- GET(artistnameURL, add_headers(Authorization = HeaderValue))
      artistname <- jsonlite::fromJSON(toJSON(content(getArtist)))
      ids <- data.frame(matrix(unlist(artistname$artists$items$id), 
                           nrow=artistname$artists$total, 
byrow=T),stringsAsFactors=FALSE)
      names <- data.frame(matrix(unlist(artistname$artists$items$name), 
                             nrow=artistname$artists$total, 
byrow=T),stringsAsFactors=FALSE)
      colnames(ids)[1]<-"Artist ID"
      colnames(names)[1]<-"Artist Name"
      artist_search <- cbind(names, ids)
      artist_search <- artist_search[1,]
      return(artist_search)
    }




    get.albums <- function(ids){
      artists_albumsURL <- paste("https://api.spotify.com/v1/artists/", ids, "/albums", sep="")
      getArtistAlbum <- GET(artists_albumsURL, add_headers(Authorization = HeaderValue))
      artistalbumname <- jsonlite::fromJSON(toJSON(content(getArtistAlbum)))
      albumids <- data.frame(matrix(unlist(artistalbumname$items$id), 
                                nrow=artistalbumname$total, 
byrow=T),stringsAsFactors=FALSE)
      albumnames <- data.frame(matrix(unlist(artistalbumname$items$name), 
                                  nrow=artistalbumname$total, 
byrow=T),stringsAsFactors=FALSE)
      artistid2 <- data.frame(matrix(unlist(artistalbumname$items$artists[[1]]$id), 
                                 nrow=artistalbumname$total, 
byrow=T),stringsAsFactors=FALSE)
      artistname2 <- 
data.frame(matrix(unlist(artistalbumname$items$artists[[1]]$name), 
                                   nrow=artistalbumname$total, byrow=T),stringsAsFactors=FALSE)

      colnames(albumids)[1]<-"Album IDs"
      colnames(albumnames)[1]<-"Album Name"
      colnames(artistid2)[1]<-"Artist ID"
      colnames(artistname2[1])<-"Artist Name"
      album_search <- cbind(artistid2, artistname2, albumnames, albumids)
      album_search <- unique(album_search)
      return(album_search)
    }


    get.tracks <- function(spotify){
      albumTracksURL <- paste("https://api.spotify.com/v1/albums/", spotify, "/tracks?limit=50", sep="")
      getTracks <- GET(albumTracksURL, add_headers(Authorization = HeaderValue))
      albumTracks <- jsonlite::fromJSON(toJSON(content(getTracks)))

      ids <- data.frame(matrix(unlist(albumTracks$items$id), 
                           nrow=albumTracks$total, byrow=T),stringsAsFactors=FALSE)

      names <- data.frame(matrix(unlist(albumTracks$items$name), 
                             nrow=albumTracks$total, byrow=T),stringsAsFactors=FALSE)
      artists<-albumTracks$items$artists
      artists1<-do.call(rbind, lapply(artists, function(x) do.call(cbind, lapply(x[c('id', 'name')], toString))))

      result <- cbind(ids, names, artists1)

      colnames(result) <- c("ID", "NAME", "ARTIST ID", "ARTIST NAME")
      result$AlbumID <- spotify
      return(result)
    }


server <- function(input, output, session) {
    ids <- reactive({
        randomVals <- eventReactive(input$goButton, input$albumId)
        spotify <- c(randomVals())
        df1 <- lapply(spotify, get.artist)
        result2 <- do.call(rbind, df1)
        result2_final<-result2
        result2_final$`Artist ID`
    })

    result_final <- reactive({
        df <- lapply(ids(), get.albums)
        result <- do.call(rbind, df)
        colnames(result)[2]<-"Artist Name"
        result
    })

   # Observes and updates album selection part
   observe({
        albums <- unique(result_final()$`Album Name`)
        updateSelectInput(session, "selectinputid",
                          label = "selectinputid",
                          choices = albums,
                          selected = albums[1])
    })

    output$result <- renderTable({
        spotify<-result_final()$`Album IDs`
        df <- lapply(spotify, get.tracks)
        result <- do.call(rbind, df)
        result_final2<-result
        names(result_final2) <- c("ID", "NAME", "ARTIST ID", "ARTIST NAME")
        final<-result_final2
        final1<-final[!duplicated(final), ]    
        final2 <- final1[!duplicated(final1[2:5]),]
        colnames(final2)[5]<-"Album ID"    
        with_album_name<-left_join(final2,result_final(), by=c("Album ID" = "Album IDs"))
        with_album_name <- with_album_name[,-c(6:7)] 
        randomVals2 <- eventReactive(input$goButton1, input$selectinputid)
        target <- c(randomVals2())
        result_final<-filter(with_album_name, `Album Name` %in% target)
        final2<-result_final
        final2
    })
}




shinyApp(ui, server)


来源:https://stackoverflow.com/questions/46352515/reactive-selectinput-dataset-unknown-until-api-call-from-previous-filter

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!