2016-08-21 24 views
5

Veri yapısı iç içe:d3.js: Erişim verileri aşağı 2 seviye

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

erişmeye istediğiniz değerler verilerdir [a] Değerler, [b] değerler kullanılır

.count daire arsa benim arsa için

kodu daireler çizmek için:

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

sorun olduğunu i = 1 becaus olduğunu nesnenin içindeki konumunun e.

Yapmak istediklerim values altında objects tüm aracılığıyla döngü etmektir. Bunu nasıl yapabilirim?

Düzenleme: Verileri değiştirmeden, becerilerimi geliştirmek için bunu nasıl yapacağınızı öğrenmek istiyorum.

Teşekkürler.

cevap

4

Veri dizinizi düzenlemek için en kolay yol, lib gibi underscore.js kullanmaktır. çizgi Dokümanlar

:

iç içe geçmiş bir dizi (iç içe herhangi bir derinliğe kadar olabilir) düzleştirir _.flatten (dizi [sığ]) düzleştirin. Eğer sığ geçerseniz,> dizi sadece tek bir seviyede düzleştirilecektir.

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

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

harita _.map (liste, iteratee [bağlam]) ad: toplamak yoluyla> dönüştürme işlevi (iteratee) listedeki her değer eşleyerek yeni bir değerler dizisi üretir. Yinelemenin üç argümanı geçmesi:> değeri, ardından iterasyonun indeksi (veya anahtarı) ve son olarak> tüm listeye bir başvuru. Kodunuzda

_.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

böyle bir şey yapabilirsiniz:

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

sayesinde, ancak verileri değiştirmeden sadece saf JS veya d3 ile yapmak mümkündür: Bütün bu kodu "run kod parçacığını" tıklayın görmek ? Becerilerimi geliştirmek istiyorum :) – Shawn

+0

@shawn Elbette yapabilirsin. Underscore.js açık kaynaktır, işlerin nasıl yapıldığını kontrol edebilirsiniz. Anlaması zor değil. Kod burada: http://underscorejs.org/underscore.js Bunu, verileri değiştirmeden d3 ile kolayca yapamazsınız ... Bir yolu var, ama bu optimize değil. Bir foreach verisi seçersiniz, sonra focus.selectAll değerlerini yapın ve çevrelerinizi bu şekilde ekleyin. – rm4

1

başka kütüphaneye olmadan ve yapmadan sadece D3 kullanarak istediğiniz neyi yapmanın birkaç yolu vardır verileri değiştirmek. Bunlardan biri, "daha yüksek" veri düzeyleriyle (iç içe geçmiş verilerle ilgili) ilgilenmek için groups kullanıyor. en bu kodda görelim:

Birincisi, tıpkı sizinki gibi bir veri kümesi kadar alay:

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}] 
    } 
]; 

Biz kullanacağım konum veridir.

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

Şimdi çoğu gelir: o yüzden en (valuesx ve y) ikinci veri düzeyini erişen ölçekler için etki alanlarını belirlemenize olanak sağlar olacak burada (sadece bir örnek olarak) serpme çizim yapmak değilim önemli kısmı:

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

kez biz 2 nesneleri ilk veri seviyesinde, D3 bizim için 2 grupları oluşturur: biz değil çember elemanlarına "gruplar" e olacak Bind verilerini konum. grupları oluşturulduğunda, biz çevreler oluşturabilir

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

Şimdi: Aksi Kutunun kırmızı, name "erkek" ise, daire mavi:

Ben de çevrelerin renklerini ayarlamak için gruplar kullanılır verileri aşağıdaki gibi bağlayıcı, her bir grubun veri values e göre

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

, function(d){ return d.values}values diziler içindeki nesnelere göre çevrelerine veri bağlanacaktır.

Ve sonra çevrelerinizi konumlandırın. Çalışır,

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

Teşekkürler, çok net bir örnek, yeni bir şey öğrendim :) – Shawn