2016-08-21 17 views
5

データ構造を2レベルをダウンネストAccessデータ:d3.js:

var data = [ 
    {name: "male", 
    values: [ 
    { count: 12345, 
     date: Date 2015-xxx, 
     name: "male" }, 
    {...} 
    ] 
    }, 
    {name: "female", 
    values: [ 
    { count: 6789, 
     date: Date 2015-xxx, 
     name: "female" }, 
    {...} 
    ] 
    } 
] 

Iアクセスする値がデータである[A] .valuesは、[B]の値が使用されている

を.count円プロットのための私のプロット

コードを円を描くように:

focus.selectAll(".dot") 
    .data(data) 
    .enter().append("circle") 
    .attr("class", "dot") 
    .attr("cx", function(d,i) { return x(d.values[i].date); }) 
    .attr("cy", function(d,i) { return y(d.values[i].count); }) 
    .attr("r", 4) 
    .style("fill", function(d,i) { return color(d.values[i].name); }) 

問題はi = 1あるbecaus eをオブジェクト内のその位置に置き換えます。

私がしたいことは、objectsのすべてをvaluesの下にループすることです。どうやってやるの?

編集:データを変更せずに自分のスキルを向上させる方法を学びたい。

ありがとうございました。

答えて

4

最も簡単な方法は、underscore.jsのようなライブラリを使用してデータ配列を編集することです。アンダードキュメントから

_.flatten(配列[浅い])を平坦化 は、ネストされた配列(ネストは、任意の深さであることができる)平坦化します。浅いを渡すと、>配列は単一のレベルでしか平坦化されません。

_.flatten([1, [2], [3, [[4]]]]); 
-> [1, 2, 3, 4]; 

_.flatten([1, [2], [3, [[4]]]], true); 
-> [1, 2, 3, [[4]]]; 

マップ _.map(リスト、iteratee、[コンテキスト])別名: >は変換関数(iteratee)を介してリスト内の各値をマッピングすることによって値の新しい配列を生成集めます。 iterateeには3つの引数が渡されます:>値、次に反復のインデックス(またはキー)、そして最後に>完全なリストへの参照です。あなたのコードで

_.map([1, 2, 3], function(num){ return num * 3; }); 
=> [3, 6, 9] 
_.map({one: 1, two: 2, three: 3}, function(num, key){ return num * 3; }); 
=> [3, 6, 9] 
_.map([[1, 2], [3, 4]], _.first); 
=> [1, 3] 

Underscore documentation

あなたがそのような何かを行うことができます。

var flatData = _.flatten(_.map(data, (d)=>d.values)); 
focus.selectAll(".dot") 
    .data(data) 
    .enter().append("circle") 
    .attr("class", "dot") 
    .attr("cx", function(d,i) { return x(d.date); }) 
    .attr("cy", function(d,i) { return y(d.count); }) 
    .attr("r", 4) 
.style("fill", function(d,i) { return color(d.name); }) 
+2

おかげで、それは動作しますが、それは、データを変更することなく、ただ純粋なJSまたはD3でそれを行うことが可能です?私は自分のスキルを向上させたい:) – Shawn

+0

@shawnもちろんできます。 Underscore.jsはオープンソースなので、状況を確認できます。理解するのは難しいことではありません。ここでコードする:http://underscorejs.org/underscore.js データを変更せずにd3で簡単に行うことはできません...方法はありますが、最適化されていません。 foreachデータを作成してから、値の上にfocus.selectAllを行い、そのようにサークルを追加します。 – rm4

1

他のライブラリなしとせずに、あなたが唯一のD3を使ってやりたいことにはいくつかの方法がありますが、データを変更する。そのうちの1つはを使用して、データの上位レベル(ネストされたデータに関する)に対処しています。のは、このコードでそれを見てみましょう:

まず、私はちょうどあなたのようなデータセットを嘲笑:

var data = [ 
    {name: "male", 
    values: [{ x: 123,y: 234}, 
     { x: 432,y: 221}, 
     { x: 199,y: 56}] 
    }, 
    {name: "female", 
    values: [{ x: 223,y: 111}, 
     { x: 67,y: 288}, 
     { x: 19, y: 387}] 
    } 
]; 

これは、我々はつもり使用しているデータがあります。

var xScale = d3.scaleLinear().range([20, 380]) 
    .domain([0, d3.max(data, function(d){ 
     return d3.max(d.values, function(d){ 
      return d.x; 
     }) 
})]); 

var yScale = d3.scaleLinear().range([20, 380]) 
    .domain([0, d3.max(data, function(d){ 
     return d3.max(d.values, function(d){ 
      return d.y; 
     }) 
})]); 

今ほとんどが来る:私はそう、のは、データの第二のレベル(values内部xy)にアクセススケールのドメインを設定でき、つもりは(単なる例として)ここでは散布図を作りますよ重要な部分は:私たちは、データ「グループ」に、ないサークル要素へのつもりバインドしている:

var circlesGroups = svg.selectAll(".circlesGroups") 
    .data(data) 
    .enter() 
    .append("g") 
    .attr("fill", function(d){ return (d.name == "male") ? "blue" : "red"}); 

は、一度データの最初のレベルでは、我々は2つのオブジェクトを持って、D3は、私たちのために2つのグループを作成します。

私はまた、円の色を設定するためにグループを使用:nameは「男性」であれば、円は青で、それ以外の場合は赤です:今

.attr("fill", function(d){ return (d.name == "male") ? "blue" : "red"}); 

、作成されたグループで、我々は円を作成します次のようにデータを結合、各グループのデータでvaluesに従って:

ここ
var circles = circlesGroups.selectAll(".circles") 
     .data(function(d){ return d.values}) 
     .enter() 
     .append("circle"); 

function(d){ return d.values}valuesアレイ内のオブジェクトに応じてサークルにデータを結合します。

あなたのサークルを配置します。これは、全体のコードで、それを見るために、「実行コードスニペット」をクリックします。

var data = [ 
 
    {name: "male", 
 
    values: [{ x: 123,y: 234}, 
 
     { x: 432,y: 221}, 
 
     { x: 199,y: 56}] 
 
    }, 
 
    {name: "female", 
 
    values: [{ x: 223,y: 111}, 
 
     { x: 67,y: 288}, 
 
     { x: 19, y: 387}] 
 
    } 
 
]; 
 

 
var xScale = d3.scaleLinear().range([20, 380]) 
 
\t .domain([0, d3.max(data, function(d){ 
 
\t \t \t return d3.max(d.values, function(d){ 
 
\t \t \t \t return d.x; 
 
\t \t }) 
 
\t })]); 
 
\t \t 
 

 

 
var yScale = d3.scaleLinear().range([20, 380]) 
 
    .domain([0, d3.max(data, function(d){ 
 
\t \t \t return d3.max(d.values, function(d){ 
 
\t \t \t \t return d.y; 
 
\t \t }) 
 
\t })]); 
 

 
var xAxis = d3.axisBottom(xScale).tickSizeInner(-360); 
 
var yAxis = d3.axisLeft(yScale).tickSizeInner(-360); 
 

 
var svg = d3.select("body") 
 
\t .append("svg") 
 
\t .attr("width", 400) 
 
\t .attr("height", 400); 
 

 
svg.append("g") 
 
\t .attr("class", "x axis") 
 
\t .attr("transform", "translate(0,380)") 
 
\t .call(xAxis); 
 
\t 
 
svg.append("g") 
 
\t .attr("class", "y axis") 
 
\t .attr("transform", "translate(20,0)") 
 
\t .call(yAxis); 
 
\t 
 
var circlesGroups = svg.selectAll(".circlesGroups") 
 
\t .data(data) 
 
\t .enter() 
 
\t .append("g") 
 
\t .attr("fill", function(d){ return (d.name == "male") ? "blue" : "red"}); 
 
\t 
 
var circles = circlesGroups.selectAll(".circles") 
 
\t .data(function(d){ return d.values}) 
 
\t .enter() 
 
\t .append("circle"); 
 
\t \t 
 
circles.attr("r", 10) 
 
\t .attr("cx", function(d){ return xScale(d.x)}) 
 
\t .attr("cy", function(d){ return yScale(d.y)});
.axis path, line{ 
 
\t stroke: gainsboro; 
 
}
<script src="https://d3js.org/d3.v4.min.js"></script>

+0

ありがとう、それは非常に明確な例です、私は何か新しいことを学んだ:) – Shawn