【问题标题】:Reactive SelectInput (Dataset Unknown until API call from Previous Filter)反应式 SelectInput(数据集未知,直到从上一个过滤器调用 API)
【发布时间】:2018-03-03 07:30:34
【问题描述】:

我正在创建一个闪亮的应用程序,它将使用 Spotify 的 API 执行以下操作:

1) 您手动输入艺术家姓名

2) 在 selectInput 中,相册需要自动填充以供您选择。

3) 选择专辑后,主面板中的表格将显示歌曲、艺术家和专辑。

到目前为止,我已经完成了这项工作,但我不知道如何进行第二部分,即在选择艺术家后自动填充专辑。我在这里问了一个之前的问题:Shiny: Automatic SelectInput Value Update Based on Previous Filter 但我意识到,问了这个问题后,数据集一开始是不知道的,供您在 ui 中引用。

所以不要这样做:

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

我想这样做:

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

代码如下:

# 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.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
   })})

输出:

在 ui 部分,我需要找到一种方法来引用 with_album_name 表,但该表是在服务器部分创建的。不确定如何做到这一点,因为现在我所要做的就是手动输入专辑名称以供选择,而当我想在 spotify 数据库中引用其他艺术家时,这将不起作用。

【问题讨论】:

  • 你问如何更新output$result
  • 不,我在问如何更新 selectInput 选项卡:“Album #1 to Select:” 目前,我正在手动输入“Yeezus”、“Graduation”等,但我想要这个动态更改为手动输入的艺术家的所有可用专辑

标签: r shiny shiny-server


【解决方案1】:

我覆盖了你的服务器部分:

  • 将所有功能移出(我更喜欢将服务器功能保存在单独的文件中);

  • 重构的服务器代码:所有代码都返回单个表。我现在添加了observeEvent 来更新列表

selectInput 部分的细微变化:

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

服务器部分:

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
    })
}

所有代码(乱七八糟):

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)

【讨论】:

  • 谢谢,我是将get.artists 放在ids 变量之前还是之后?你介意把完整的剧本放进去吗?无需包含 ui 部分,因为这并没有太大变化。感谢您的帮助!
  • 谢谢!有什么原因,为什么在这个新版本中侧面板被截断到页面的一半?
  • @NickKnauer 我在我的机器上看不到它......它不应该,因为它是一个 ui 的东西,我在那里没有改变太多。如果我的解决方案解决了您的问题,您可以接受我的回答。
  • @PoGibas :为什么需要在 server.R 代码的起始行中使用 reactive() 函数包装 eventReactive()eventReactive 不是一个足够好的反应上下文吗?
猜你喜欢
  • 2019-01-11
  • 2016-01-10
  • 2014-08-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-22
  • 2017-01-17
  • 1970-01-01
相关资源
最近更新 更多