2012-04-10 38 views
35

Tôi mới sử dụng D3 và đã dành một vài giờ để tìm hiểu bất kỳ điều gì về việc xử lý dữ liệu có cấu trúc nhưng không có kết quả tích cực. Tôi muốn tạo biểu đồ thanh bằng cấu trúc dữ liệu bên dưới. Thanh được vẽ (theo chiều ngang), nhưng chỉ dành cho người dùng "jim".D3 - cách xử lý cấu trúc dữ liệu JSON?

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

Bất kỳ ai có thể chỉ ra những gì tôi đã làm sai?

Trả lời

85

Khi bạn join data đến lựa chọn qua selection.data, số phần tử trong mảng dữ liệu của bạn phải khớp với số phần tử trong lựa chọn. Mảng dữ liệu của bạn có hai phần tử (cho Jim và Ray), nhưng lựa chọn bạn đang ràng buộc nó chỉ có một phần tử SVG. Bạn đang cố gắng tạo nhiều phần tử SVG, hoặc đặt điểm số cho cả Jim và Ray trong cùng một phần tử SVG?

Nếu bạn muốn để ràng buộc cả hai yếu tố dữ liệu đến các yếu tố SVG số ít, bạn có thể quấn các dữ liệu trong mảng khác:

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

Ngoài ra, sử dụng selection.datum, mà liên kết với dữ liệu trực tiếp mà không cần tính toán một tham gia:

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

Nếu bạn muốn tạo nhiều yếu tố SVG cho mỗi người, sau đó bạn sẽ cần một dữ liệu tham gia:

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

Vấn đề thứ hai là bạn không nên sử dụng d3.values với một mảng; chức năng đó là để trích xuất các giá trị của một đối tượng. Giả sử bạn muốn một yếu tố SVG mỗi người (như vậy, hai trong ví dụ này), sau đó các dữ liệu cho rect chỉ đơn giản là điểm liên quan của người đó:

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

Nếu bạn chưa sẵn sàng, tôi khuyên bạn nên đọc những hướng dẫn:

+1

Xin chào Mike, tôi rất vinh dự khi nhận được sự giúp đỡ từ bạn :) Điều tôi muốn trong ví dụ này là lấy một SVG hình ảnh. Dường như lỗi của tôi đã không được sử dụng .data ([dữ liệu]), chỉ cần .data (dữ liệu) thay thế. Thật không may tôi không thể kiểm tra nó cùng một lúc, nhưng tôi sẽ làm điều đó vào tối nay. Tôi đã lướt qua "các lựa chọn lồng nhau" trước đây. Điều đó dường như không bao gồm chủ đề này, nhưng kể từ khi bạn đề xuất nó, tôi sẽ đi sâu vào các hướng dẫn này. Tôi sẽ cập nhật bài đăng này. Cảm ơn! – Ray

+5

Vui vì tôi có thể giúp. Nếu điều này trả lời câu hỏi của bạn, vui lòng thêm dấu kiểm để giải quyết. Cảm ơn! – mbostock

+0

Xin chào một lần nữa, giải pháp đó không hoạt động. Lần này không có hình ảnh nào trong thời gian này: \ – Ray

1

Điều này có thể làm sáng tỏ các khía cạnh lồng nhau, ngoài của mbostock câu trả lời tốt.

Dữ liệu của bạn có 2 độ lồng. Bạn có một mảng gồm 2 đối tượng, mỗi đối tượng có một mảng int. Nếu bạn muốn hình ảnh cuối cùng của bạn phản ánh những khác biệt này, bạn cần phải tham gia cho mỗi sự khác biệt.

Đây là một giải pháp: Mỗi người dùng được thể hiện bằng một phần tử nhóm g, với mỗi điểm được đại diện bởi rect. Bạn có thể thực hiện việc này theo một vài cách: Hoặc sử dụng datum trên svg, sau đó là chức năng nhận dạng trên mỗi g hoặc bạn có thể trực tiếp tham gia dữ liệu trên g.Sử dụng data trên g là điển hình hơn, nhưng đây là cả hai cách:

Sử dụng dữ kiện trên 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); 

sử dụng dữ liệu về nhóm (g) yếu tố:

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

Một lần nữa, bạn không phải tạo các phần tử g này, nhưng bằng cách làm như vậy bây giờ tôi có thể đại diện cho điểm số của người dùng khác nhau (họ có differe nt y từ biến đổi) và tôi cũng có thể cung cấp cho họ các kiểu khác nhau, như sau:

.jim { 
    fill: red; 
} 
.ray { 
    fill: blue; 
} 
Các vấn đề liên quan