web-dev-qa-db-ja.com

D3-JSONデータ構造の処理方法

私はD3の初心者であり、構造化されたデータの取り扱いについて何かを見つけるために既に数時間を費やしましたが、肯定的な結果はありませんでした。以下のデータ構造を使用して棒グラフを作成します。バーは(水平方向に)描画されますが、ユーザー "jim"専用です。

var data = [{"user":"jim","scores":[40,20,30,24,18,40]},
            {"user":"ray","scores":[24,20,30,41,12,34]}];

var chart = d3.select("div#charts").append("svg")                                   
              .data(data)
              .attr("class","chart")
              .attr("width",800)
              .attr("height",350);

chart.selectAll("rect")    
    .data(function(d){return d3.values(d.scores);})    
    .enter().append("rect")
    .attr("y", function(d,i){return i * 20;})
    .attr("width",function(d){return d;})
    .attr("height", 20);

誰かが私が間違ったことを指摘できますか?

36
Ray

データの結合 を介して選択に selection.data を指定すると、データ配列の要素の数が選択の要素の数と一致する必要があります。データ配列には2つの要素(JimとRayの場合)がありますが、バインドする選択には1つのSVG要素しかありません。複数のSVG要素を作成しようとしていますか、それとも同じSVG要素にJimとRayの両方のスコア四角形を配置しようとしていますか?

両方のデータ要素を単一のSVG要素にバインドする場合は、データを別の配列にラップできます。

var chart = d3.select("#charts").append("svg")
    .data([data])
    .attr("class", "chart")
    …

または、 selection.datum を使用します。これは、結合を計算せずにデータを直接バインドします。

var chart = d3.select("#charts").append("svg")
    .datum(data)
    .attr("class", "chart")
    …

ユーザーごとに複数のSVG要素を作成する場合は、データ結合が必要になります。

var chart = d3.select("#charts").selectAll("svg")
    .data(data)
  .enter().append("svg")
    .attr("class", "chart")
    …

2番目の問題は、配列で d3.values を使用しないでください。その関数は、オブジェクトの値を抽出するためのものです。 1人あたり1つのSVG要素(この例では2つ)が必要だとすると、rectのデータはその人に関連付けられたスコアだけになります。

var rect = chart.selectAll("rect")
    .data(function(d) { return d.scores; })
  .enter().append("rect")
    …

まだお持ちでない場合は、次のチュートリアルを読むことをお勧めします。

92
mbostock

これにより、mbostockの優れた答えに加えて、ネストされた側面が明確になります。

データには2度のネストがあります。 2つのオブジェクトの配列があり、それぞれにintの配列があります。最終画像にこれらの違いを反映させたい場合は、それぞれに対して結合を行う必要があります。

1つの解決策は次のとおりです。各ユーザーはグループg要素で表され、各スコアはrectで表されます。これにはいくつかの方法があります。svgでdatumを使用し、次に各gで恒等関数を使用するか、gでデータを直接結合できます。 datagを使用するのがより一般的ですが、両方の方法があります。

svg:でのデータムの使用

var chart = d3.select('body').append('svg')
  .datum(data)             // <---- datum
  .attr('width',800)
  .attr('height',350)
  .selectAll('g')
  .data(function(d){ return d; })  // <----- identity function
  .enter().append('g')
    .attr('class', function(d) { return d.user; })
    .attr('transform', function(d, i) { return 'translate(0, ' + i * 140 + ')'; })
    .selectAll('rect')
    .data(function(d) { return d.scores; })
    .enter().append('rect')
      .attr('y', function(d, i) { return i * 20; })
      .attr('width', function(d) { return d; })
      .attr('height', 20);

グループ(g)要素のデータを使用:

var chart = d3.select('body').append('svg')
  .attr('width',800)
  .attr('height',350)
  .selectAll('g')
  .data(data)          // <--- attach directly to the g
  .enter().append('g')
    .attr('class', function(d) { return d.user; })
    .attr('transform', function(d, i) { return 'translate(0, ' + i * 140 + ')'; })
    .selectAll('rect')
    .data(function(d) { return d.scores; })
    .enter().append('rect')
      .attr('y', function(d, i) { return i * 20; })
      .attr('width', function(d) { return d; })
      .attr('height', 20);

繰り返しますが、これらのg要素を作成する必要はありませんが、そうすることで、ユーザースコアを異なる方法で表現できるようになり(変換と異なるyがあります)、次のように異なるスタイルを与えることもできます。

.jim {
  fill: red;
}
.ray {
  fill: blue;
}
1
Tristan Reid