2014-10-10 1 views
1

JSON 페이로드에서 생성 된 다중 문서 라인 차트의 기본 데모가 있습니다. 예상대로 작동하지만 데이터를 올바르게 파싱하거나 바인딩 할 때 D3 라이브러리를 최대한 활용하지 못한다는 것을 알고 있습니다.JSON에서 D3 Multiseries Line Chart

중첩 데이터에 가장 적합한 형식은 무엇입니까? 예를 들어, 객체의 객체, 배열의 배열 등?

http://jsfiddle.net/thinkin3d/nc2sgmcz/

json으로 페이로드는 다음과 같습니다

내가 배열로 변환하는 d3.entries 전화
var data = { 
    "Series 1": { 
     "20141020": 3.5003987252672744, 
     "20141019": 2.505802351020492, 
     "20141018": 1.511804171940014}, 
    "Series 2": { 
     "20141008": 3.386547593121662, 
     "20141009": 2.1369256424188166, 
     "20141010": 0.88701610875722286}, 
    "Series 3": { 
     "20141024": 1.041445076319178, 
     "20141025": 1.1241181263211502, 
     "20141026": 1.38667149365412} 
} 

:

var entries = d3.entries(data); 

그리고 내가 d3.entries 다시 전화 내가 두 번째 Tier에서 특정 키 - 값 쌍에 액세스 할 때마다 :

var entry = d3.entries(d.value); 

나는 이것을 여러 번 부르고 반복한다. 그래서 내가 잘 모르는 더 좋은 방법이 있어야한다는 것을 느낀다.

D3 라이브러리의 어떤 부분을 활용하지 않습니까?

이상적으로 JSON 페이로드 형식을 유지할 수 있기를 원하지만 간단한 재 배열을 통해 전달하기 전에 D3을 사용하면 훨씬 쉽게 작업 할 수 있습니다.

코드 :

var margin = {top: 20, right: 20, bottom: 30, left: 50}, 
     width = 600 - margin.left - margin.right, 
     height = 400 - margin.top - margin.bottom; 

var parseDate = d3.time.format("%Y%m%d").parse; 

var x = d3.time.scale() 
     .range([0, width]); 

var y = d3.scale.linear() 
     .range([0, height]); 

var color = d3.scale.category20(); 

var xAxis = d3.svg.axis() 
     .scale(x) 
     .orient("bottom"); 

var yAxis = d3.svg.axis() 
     .scale(y) 
     .orient("left"); 

var area = d3.svg.area() 
     .interpolate("basis") 
     .x(function (d) { 
      return x(parseDate(d.key)); 
     }) 
     .y0(height) 
     .y1(function (d) { 
      return y(d.value); 
     }); 

var svg = d3.select("body").append("svg") 
     .attr("width", width + margin.left + margin.right) 
     .attr("height", height + margin.top + margin.bottom) 
     .append("g") 
     .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); 

var entries = d3.entries(data); 

color.domain(entries.map(function (d) { 
    return d; 
})); 

var minX = d3.min(entries, function (kv) { 
    var entry = d3.entries(kv.value); 
    return d3.min(entry, function (d) { 
     return parseDate(d.key); 
    }) 
}); 
var maxX = d3.max(entries, function (kv) { 
    var entry = d3.entries(kv.value); 
    return d3.max(entry, function (d) { 
     return parseDate(d.key); 
    }) 
}); 
var minY = d3.min(entries, function (kv) { 
    var entry = d3.entries(kv.value); 
    return d3.min(entry, function (d) { 
     return d.value; 
    }) 
}); 
var maxY = d3.max(entries, function (kv) { 
    var entry = d3.entries(kv.value); 
    return d3.max(entry, function (d) { 
     return d.value; 
    }) 
}); 

x.domain([minX, maxX]); 
y.domain([minY, maxY]); 

var element = svg.selectAll(".element") 
     .data(entries) 
     .enter().append("g") 
     .attr("class", "element"); 

element.append("path") 
     .attr("class", "area") 
     .attr("d", function (d) { 
      var entry = d3.entries(d.value); 
      return area(entry); 
     }) 
     .style("fill", function (d) { 
      return color(d.key); 
     }); 

element.append("text") 
     .datum(function (d) { 
      var entry = d3.entries(d.value); 
      return { 
       name: d.key, 
       date: parseDate(entry[entry.length - 1].key), 
       value: entry[entry.length - 1].value 
      }; 
     }) 
     .attr("transform", function (d) { 
      return "translate(" + x(d.date) + "," + y(d.value) + ")"; 
     }) 
     .attr("x", -6) 
     .attr("dy", ".35em") 
     .text(function (d) { 
      return d.name; 
     }); 

svg.append("g") 
     .attr("class", "x axis") 
     .attr("transform", "translate(0," + height + ")") 
     .call(xAxis); 

svg.append("g") 
     .attr("class", "y axis") 
     .call(yAxis); 
+0

fddle it. 더 나은, plunkr. –

+0

http://jsfiddle.net/thinkin3d/nc2sgmcz/ –

답변

0

먼저 모든 x와 y 값 다음 해당 배열의 범위를 얻을 상당히 경우 당신은 당신의 코드를 단순화 할 수 있습니다. 이것은 오직주의 당신이 중첩 배열 평평 할 필요가있는 비교적 간단합니다 :

var allX = d3.values(data).map(d3.keys) 
    .reduce(function(a,b) { return a.concat(b); }).map(parseDate); 
var allY = d3.values(data).map(d3.values) 
    .reduce(function(a,b) { return a.concat(b); }); 

x.domain(d3.extent(allX)); 
y.domain(d3.extent(allY)); 

이 초기 데이터 구조의 값을 얻고을 원하는 여부에 따라 그 중 하나를 키 또는 값의 각 x 또는 y. 이 중첩 배열은 .reduce()을 사용하여 병합됩니다. y에 대해서, 우리는 끝났습니다. x에 대해, 날짜는 파싱됩니다. 그런 다음 d3.extend()을 직접 사용하여 도메인 값을 가져올 수 있습니다.

완료 데모 here.

관련 문제