La regla general al usar un data-join es que desea un mapeo uno a uno de los datos a los elementos. Entonces, si tiene dos series en su diagrama de dispersión, querrá dos elementos de contenedor (como G elements) para representar la serie. Como actualmente solo tiene una matriz data
, también querrá usar array.map para convertir la representación de datos en dos matrices paralelas con la misma representación. De esta forma, no tienes que duplicar el código para cada serie.
que dicen sus datos se representan en un archivo CSV con una columna para los x-valores, y varias otras columnas para la y-valores de cada serie:
x,y1,y2
5,90,22
25,30,25
45,50,80
65,55,9
85,25,95
Si desea que el el código es completamente genérico, primero debe calcular los nombres de la serie, como ["y1", "y2"]
. (Si agregó una tercera columna al archivo CSV, podría ser ["y1", "y2", "y3"]
). Puede calcular los nombres usando d3.keys, que extrae las propiedades nombradas de un objeto. Por ejemplo, d3.keys({foo: 1, bar: 2})
devuelve ["foo", "bar"]
.
// Compute the series names ("y1", "y2", etc.) from the loaded CSV.
var seriesNames = d3.keys(data[0])
.filter(function(d) { return d !== "x"; })
.sort();
Ahora que tiene los nombres de las series, puede crear una matriz de matrices de puntos. La matriz externa representa la serie (de los cuales hay dos) y las matrices internas almacenan los puntos de datos. Puede convertir los puntos simultáneamente en una representación coherente (objetos con las propiedades x
y y
), lo que le permite reutilizar el código en series.
// Map the data to an array of arrays of {x, y} tuples.
var series = seriesNames.map(function(series) {
return data.map(function(d) {
return {x: +d.x, y: +d[series]};
});
});
Nota Este código utiliza el operador +
para forzar a los valores de CSV a los números. (Los archivos CSV están sin tipo, por lo que inicialmente son cadenas).)
Ahora que ha mapeado sus datos a un formato regular, puede crear elementos G para cada serie, y luego rodear los elementos dentro de cada punto. La estructura SVG resultante tendrá este aspecto:
<g class="series">
<circle class="point" r="4.5" cx="1" cy="2"/>
<circle class="point" r="4.5" cx="3" cy="2"/>
…
</g>
<g class="series">
<circle class="point" r="4.5" cx="5" cy="4"/>
<circle class="point" r="4.5" cx="7" cy="6"/>
…
</g>
y el correspondiente código D3:
// Add the points!
svg.selectAll(".series")
.data(series)
.enter().append("g")
.attr("class", "series")
.style("fill", function(d, i) { return z(i); })
.selectAll(".point")
.data(function(d) { return d; })
.enter().append("circle")
.attr("class", "point")
.attr("r", 4.5)
.attr("cx", function(d) { return x(d.x); })
.attr("cy", function(d) { return y(d.y); });
También he añadido un poco de código para asignar cada serie un color único mediante la adición de un estilo de relleno al elemento G que contiene. Hay muchas formas diferentes de hacer esto, por supuesto. (Es posible que desee ser más específico sobre el color de cada serie, por ejemplo.) También he omitido el código que calcula los dominios de sus escalas x y y (además de representar los ejes), pero si quieres ver todo el ejemplo de trabajo:
casi un tutorial ... esta y las otras preguntas similares que fueron respondidas a través de respuestas tan largas por Mike Bostock deberían incluirse en las preguntas más frecuentes – paxRoman