2012-07-26 14 views
12

Todos los tutoriales de d3 que he encontrado usan datos dispuestos en matrices de objetos a partir de los cuales grafican un punto para cada objeto en la matriz. Datos dados en la siguiente estructura:¿Puede d3.js dibujar dos diagramas de dispersión en el mismo gráfico utilizando datos de la misma fuente?

data = [ 
    {id: 1, x: 4, y: 10, type: 1}, 
    {id: 2, x: 5, y: 20, type: 2} 
    ... 
] 

Los valores xey se usan para hacer un diagrama de dispersión. El parámetro tipo se usa para cambiar el color de cada punto. Vea este jsfiddle para un ejemplo: http://jsfiddle.net/uxbHv/

Desafortunadamente, tengo una estructura de datos diferente y no puedo encontrar la manera de crear el mismo gráfico dibujando dos puntos de datos para cada objeto. He aquí algunos datos de ejemplo:

dataSet = [ 
    {xVar: 5, yVar1: 90, yVar2: 22}, 
    {xVar: 25, yVar1: 30, yVar2: 25}, 
    {xVar: 45, yVar1: 50, yVar2: 80}, 
    {xVar: 65, yVar1: 55, yVar2: 9}, 
    {xVar: 85, yVar1: 25, yVar2: 95} 
] 

puedo graficar xVar individual contra yVar1 o yVar2, pero no puedo encontrar la manera de obtener los dos en el mismo gráfico: http://jsfiddle.net/634QG/

Respuesta

30

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:

+0

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

4

Coloque los dos círculos para cada dato señalar en un solo elemento svg:g. Esto produce un mapeo uno a uno para los datos a los elementos, pero aún le permite mostrar dos puntos diferentes.

var nodeEnter = vis1.selectAll("circle") 
     .data(dataSet) 
     .enter() 
     .insert("svg:g"); 

nodeEnter.insert("svg:circle") 
      .attr("cx", function (d) { return 100 - d.xVar}) 
      .attr("cy", function (d) { return 100 - d.yVar1}) 
      .attr("r", 2) 
      .style("fill", "green"); 

nodeEnter.insert("svg:circle") 
      .attr("cx", function (d) { return 100 - d.xVar}) 
      .attr("cy", function (d) { return 100 - d.yVar2}) 
      .attr("r", 2) 
      .style("fill", "blue"); 

Trabajando JSFiddle.

+0

Gracias por la solución! Veo cómo funciona esto con datos estáticos, pero ahora me pregunto si será difícil agregar transiciones y salidas ... de vuelta a jsfiddle ... –

+0

Esto podría funcionar (ahora), pero desaconsejaría este patrón- la API no está diseñada para funcionar de esta manera. Al usar una combinación de datos, siempre debe tener una asignación de uno a uno entre los datos y los elementos. Insertar o agregar a la selección de ingresar dos veces es un uso indebido de la API. La solución correcta en este caso es crear dos elementos 'vis' y asignar los datos a dos matrices paralelas con una representación consistente. – mbostock

+0

@mbostock ¿Es este un mejor enfoque? http://jsfiddle.net/634QG/3/ –

Cuestiones relacionadas