2012-04-10 20 views
35

Soy nuevo en D3 y dediqué algunas horas a buscar información estructurada, pero sin resultado positivo. Quiero crear un gráfico de barras usando la estructura de datos a continuación. Las barras se dibujan (horizontalmente), pero solo para el usuario "jim".D3: cómo lidiar con las estructuras de datos 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); 

¿Alguien podría señalar lo que hice mal?

Respuesta

85

Cuando join data a una selección a través de selection.data, el número de elementos en su conjunto de datos debe coincidir con el número de elementos en la selección. Su matriz de datos tiene dos elementos (para Jim y Ray), pero la selección a la que lo está vinculando solo tiene un elemento SVG. ¿Estás tratando de crear múltiples elementos SVG, o poner las respuestas de puntuación tanto para Jim como para Ray en el mismo elemento SVG?

Si desea enlazar ambos elementos de datos al elemento SVG singular, se puede envolver los datos en otra matriz:

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

otra alternativa es utilizar selection.datum, que une los datos directamente sin calcular una combinación:

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

Si desea crear varios elementos SVG para cada persona, entonces se necesita un data-unes:

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

Un segundo problema es que no debe usar d3.values con una matriz; esa función es para extraer los valores de un objeto. Suponiendo que quería un elemento SVG por persona (así, dos en este ejemplo), entonces los datos para el rect es simplemente puntajes asociados de esa persona:

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

Si no lo ha hecho, recomiendo leer estos tutoriales:

+1

Hola Mike, es un honor con la obtención de la ayuda de usted :) Lo que quiero en este ejemplo, es la obtención de un único SVG imagen. Parece que mi error no fue usar .data ([data]), solo .data (data) en su lugar. Lamentablemente no puedo verificarlo de inmediato, pero lo haré esta tarde. Yo había robado "selecciones anidadas" antes. Parecía que no cubría este tema, pero como lo recomendó, profundizaré en estos tutoriales. Actualizaré esta publicación. ¡Gracias! – Ray

+5

Me alegro de poder ayudar. Si esto respondió su pregunta, agregue la marca de verificación para resolverlo. ¡Gracias! – mbostock

+0

Hola otra vez, esa solución no funciona. Esta vez no hay ninguna imagen en este momento: \ – Ray

1

esto puede aclarar el aspecto anidada, además de mbostock respuesta bien.

Sus datos tienen 2 grados de anidamiento. Tienes una matriz de 2 objetos, cada uno tiene una matriz de enteros. Si quieres que tu imagen final refleje estas diferencias, debes unirte a cada una.

Aquí hay una solución: cada usuario está representado por un elemento de grupo g, con cada puntuación representada por rect. Puede hacer esto de varias maneras: use datum en el svg, luego una función de identidad en cada g, o puede unir directamente los datos en el g.Usando data en el g es más típico, pero aquí hay dos maneras:

Uso de referencia en el 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); 

utilizando datos sobre el grupo (g) elemento:

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

De nuevo, no tiene que crear estos elementos g, pero al hacerlo ahora puedo representar los puntajes de los usuarios de manera diferente (tienen diferentes nt y de la transformación) y también puedo dar diferentes estilos, como este:

.jim { 
    fill: red; 
} 
.ray { 
    fill: blue; 
} 
Cuestiones relacionadas