javascript - objetos - D3: ¿cómo lidiar con las estructuras de datos JSON?
tipos de datos en javascript ejemplos (2)
Soy nuevo en D3 y dediqué unas pocas horas a buscar información sobre cómo manejar datos estructurados, pero sin resultados positivos. 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".
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?
Cuando unes datos a una selección a través de selection.data , la cantidad de elementos en tu matriz de datos debe coincidir con la cantidad 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 vincular ambos elementos de datos al elemento singular SVG, puede envolver los datos en otra matriz:
var chart = d3.select("#charts").append("svg")
.data([data])
.attr("class", "chart")
…
Alternativamente, use selection.datum , que vincula datos directamente sin calcular una unión:
var chart = d3.select("#charts").append("svg")
.datum(data)
.attr("class", "chart")
…
Si desea crear múltiples elementos SVG para cada persona, necesitará una combinación de datos:
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 desea un elemento SVG por persona (por lo tanto, dos en este ejemplo), los datos para el rect son simplemente los puntajes asociados de esa persona:
var rect = chart.selectAll("rect")
.data(function(d) { return d.scores; })
.enter().append("rect")
…
Si aún no lo has hecho, te recomiendo que leas estos tutoriales:
Esto puede aclarar el aspecto anidado, además de la buena respuesta de mbostock.
Sus datos tienen 2 grados de anidación. 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 group g
, con cada puntuación representada por un rect
. Puede hacer esto de varias maneras: use datum
en svg, luego una función de identidad en cada g
, o puede unir directamente los datos en g
. Usar data
en g
es más típico, pero aquí están las dos maneras:
Usando datum 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);
Usando datos en el elemento del grupo ( g
):
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 es necesario crear estos elementos g, pero al hacerlo ahora puedo representar los puntajes de los usuarios de manera diferente (tienen diferentes y de la transformación) y también puedo darles diferentes estilos, como este:
.jim {
fill: red;
}
.ray {
fill: blue;
}