2014-11-08 272 views
0

我搞亂了last.fm API。我拉着user's top artists data,它返回一個像這樣的JSON:d3.js:嵌套數據 - 鍵返回undefined的所有數據

{ "artist": [ 
     { 
     "name": "Kanye West", 
     "playcount": "282", 
     "mbid": "164f0d73-1234-4e2c-8743-d77bf2191051", 
     "url": "http:\/\/www.last.fm\/music\/Kanye+West", 
     "streamable": "0", 
     "@attr": { 
      "rank": "1" 
     } 
     }, 
     { 
     "name": "Childish Gambino", 
     "playcount": "148", 
     "mbid": "7fb57fba-a6ef-44c2-abab-2fa3bdee607e", 
     "url": "http:\/\/www.last.fm\/music\/Childish+Gambino", 
     "streamable": "0", 
     "@attr": { 
      "rank": "2" 
     } 
     }, 

等。經過一番小提琴之後,我爲第二個JSON(例如搖滾,流行音樂,嘻哈)拉動了第二個JSON,循環播放每位藝術家,並將他們最受歡迎的標籤推送到原始數據集。所以,現在我的JSON的樣子:

{ "artist": [ 
     { 
     "name": "Kanye West", 
     "playcount": "282", 
     "mbid": "164f0d73-1234-4e2c-8743-d77bf2191051", 
     "url": "http:\/\/www.last.fm\/music\/Kanye+West", 
     "streamable": "0", 
     "@attr": { 
      "rank": "1" 
     }, 
     "tag": "hip hop", 
     }, 
     { 
     "name": "Childish Gambino", 
     "playcount": "148", 
     "mbid": "7fb57fba-a6ef-44c2-abab-2fa3bdee607e", 
     "url": "http:\/\/www.last.fm\/music\/Childish+Gambino", 
     "streamable": "0", 
     "@attr": { 
      "rank": "2" 
     }, 
     "tag": "hip hop", 
     }, 

我想要做的下一件事是使用d3.nest使用每個標籤(流派)爲重點,以捲起我的數據。我正在關注這個tutorial。我的最終目標是製作一個sunburst,與內圈的流派(例如,你聽多少嘻哈,獨立歌曲,流行音樂?)和 - 也許點擊 - 每個藝術家你聽多少(例如Kanye West對幼稚甘比諾)。

的主要問題是在這裏:

 var dataset = d3.nest() 
         .key(function(d) { 
          return d.tag; 
         }) 
         .entries(topArtists); 

key將返回undefined所有數據點。當我嘗試其他可能的密鑰(d.name,d.streamable)時,它們工作正常。我的數據按需要捲起來。所以這與tag有關 - 這是我推送到topArtists數據集的對象。我不確定發生了什麼事。下面是我通過循環如何,並結合標籤信息,藝術家信息:

//Merge 
    topArtists.forEach(function(d) { 

     //loop through each of the top 10 artists selected 
     //pull their mbid (musicbrainz id) and plug it into the var for tags    
     tags = 'http://ws.audioscrobbler.com/2.0/?method=artist.gettoptags&mbid='+ d.mbid + '&api_key=[my api key]&format=json'; 

      //pull that JSON 
      d3.json(tags, function(error, tag) { 

       if (error) { return console.log(error); }; 

       //capture only the most commonly used tag (artistTag) 
       //and also clean it up a bit 
       artistTag = tag.toptags.tag[0].name.toLowerCase().split('-').join(' '); 

       //push that string value to the original JSON 
       d["tag"] = artistTag; 


      }); // close tags JSON call 
     }); //close topArtists loop 

關閉這些循環後,如果我console.log(topArtists),這一切看起來很好 - 標籤已被添加。 JSFiddle here

+0

問題是'd3.json'是異步的。它在'forEach'循環結束後運行。你可能想考慮一下[queue.js](https://github.com/mbostock/queue)。 – 2014-11-08 11:27:26

+0

謝謝,拉爾斯。我認爲它可能是異步的 - 但是當我運行'forEach'循環和第二個JSON調用的'console.log(topArtists)* *外部時,它看起來很好 - 所有的'tags'都被追加。如果在下一行中,我嘗試'd3.nest' - 它們會變成未定義的。事實上,即使我做了'd3.nest().key(function(d){console.log(topArtists);})',標籤也顯示出來了。由於某種原因,它們只是沒有被捲起來。 – 2014-11-08 12:58:52

+0

所以'console.log()'打印一個對象不完全正確嗎?在中,你點擊它來展開屬性等。點擊的時間實際上是在評估時。也就是說,當你打印表達式時,它不在那裏,但是當你點擊它時,就是這樣。在將數據放入數據之前和之後,您可以通過兩次打印相同的表達式來查看。當您檢查控制檯上的這些對象時,即使它們在打印時明顯不同,它們也是一樣的。 – 2014-11-08 13:09:58

回答

0

感謝Lars's suggestion yesterday,我設法使用了Mike Bostock的queue.js庫。萬一別人運行到這個問題,這裏是我遵循的步驟:

首先,我在<head>稱爲queue.js,在d3.js通話之後:

  <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script> 
      <script src="http://d3js.org/queue.v1.min.js"></script> 

我想要做的主要事情是:

  1. 用戶輸入last.fm用戶名。
  2. script拉起了一個JSON的user's top 10 (or 20, or whatever) artists
  3. 拉每位藝術家的「musicbrainz id」(一個唯一的數字標識符),並做一系列10(或20,或其他)d3.json調用來獲得artist's top tags
  4. 將最常用的tag合併爲每位藝術家的原創頂級藝術家JSON。 (藝術家可以有許多用戶編寫的tags,所以我只抽出最常用的一個。)
  5. 接下來 - 可視化。

在實踐中,這意味着第一個頂尖的藝術家(topArtists)的做了d3.json呼叫,並且,內,一個queue.js呼叫 - 其中每個queue.defer()是什麼在topArtists JSON的功能。之後,我可以循環,將tag添加到每個topArtists項目,然後使用d3.nest將我的數據排列在tags周圍,如keys

下面是這一切的樣子:

首先,外JSON呼籲topArtists。我這樣做是爲了將topArtists設置爲JSON,否則,如果我嘗試將它嵌套在queue.js之內,則最終會出現無限循環。

d3.json(top, function(error, json) { 

    if(error) { return console.log(error); } 

    topArtists = json.topartists.artist; 

接下來,以下this StackOverflow Q&A,我成立了一個queue()(1)再次從last.fm API(這是topArtists我會用前進來構建我的最終數據集)調用相同topArtists JSON ,然後(2)動態調用每個藝術家的tags API。

var q = queue() 
     .defer(d3.json, top); 

    topArtists.forEach(function(d) { 

      tags = 'http://ws.audioscrobbler.com/2.0/?method=artist.gettoptags&mbid='+ d.mbid + '&api_key=[my api key]&format=json' 

      q.defer(d3.json, tags); 

      }); 

所有這些JSONs已經被加載後,我遍歷和(後檢查的名稱相匹配),每個藝術家的標籤附加到topArtists數據,改名dataset

q.awaitAll(function() {   


      dataset = arguments[1][0].topartists.artist 

      for (var i = 1; i < arguments[1].length ; i++) { 

       var j = i - 1; 

       var artistName = arguments[1][0].topartists.artist[j].name; 
       var artistTagName = arguments[1][i].toptags['@attr'].artist; 

       if (artistName == artistTagName) { 

        artistTag = arguments[1][i].toptags.tag[0].name.toLowerCase().split('-').join(' '); 

        dataset[j]["tag"] = artistTag; 

       }; 

      }; //close for loop 

沒有收出queue.awaitAll(),我現在可以使用d3.nest挽起我的數據。現在可以在可視化中使用dataset了;這也將被稱爲.awaitAll()

  dataset = d3.nest() 
       .key(function(d) { 
        return d.tag; 
       }) 
       .entries(dataset); 

      console.log(dataset);