2016-08-21 8 views
5

데이터 구조 중첩 :d3.js : 액세스 데이터는 아래 2 레벨

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는 세 개의 인수, 즉> 값, 그리고 반복의 인덱스 (또는 키), 그리고 마지막으로> 전체 목록에 대한 참조를 전달합니다. 코드에서

_.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를 사용하여 원하는 일을 할 수있는 몇 가지 방법이 있습니다 데이터를 변경합니다. 그 중 하나는을 사용하여 중첩 된 데이터와 관련된 "상위"데이터 수준을 처리합니다. 의이 코드를 보자 :

첫째, 난 그냥 당신처럼 데이터 집합을 조롱 :

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는 우리를 위해 두 그룹을 만들 것입니다 : 우리가하지 서클 요소에 "그룹"에 거 바인드에게 데이터입니다. 그룹이 만든, 우리가 원을 만들고,

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

이제 : 그렇지 않으면 빨간색의, name는 "남성"의 경우, 원이 파란색 :

는 또한 원의 색상을 설정하기 위해 그룹을 사용 다음과 같은 데이터를 결합, 각 그룹의 데이터에 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