2012-08-29 34 views
19

Estoy construyendo un diagrama de barras en d3.js en el que cada barra representa el total de casos de TB durante un mes. Los datos consisten esencialmente en una fecha (inicialmente cadenas en formato% Y-% m, pero analizada usando d3.time.format.parse) y un entero. Me gustaría que las etiquetas de los ejes fueran relativamente flexibles (mostrar solo los límites de los años, la etiqueta cada mes, etc.), pero también me gustaría que las barras estén espaciadas uniformemente.d3.js - barras espaciadas uniformemente en una escala de tiempo

puedo conseguir el etiquetado eje flexible cuando utilizo una escala fecha:

var xScaleDate = d3.time.scale() 
    .domain(d3.extent(thisstat, function(d) { return d.date; })) 
    .range([0, width - margin.left - margin.right]); 

... pero las barras no son iguales de tiempo debido a un número variable de días de cada mes (por ejemplo, febrero y marzo están notablemente más juntos que otros meses). Puedo conseguir barras separadas uniformemente usando una escala lineal:

var xScaleLinear = d3.scale.linear() 
     .domain([0, thisstat.length]) 
     .range([0, width - margin.left - margin.right]); 

... pero no puedo encontrar la manera de continuación, tienen etiquetas de los ejes basados ​​en fechas. Intenté usar ambas escalas simultáneamente y solo generar un eje del xScaleDate, solo para ver qué pasaría, pero las escalas naturalmente no se alinean del todo bien.

¿Hay una manera directa de lograr esto que me falta?

+0

parece que el problema es que D3 es la creación xpos de la marca de tiempo real. ¿Qué tal calcular 'data.monthsFromJan2000' o similar y usar eso como su entrada de datos para xpos? De esa manera estarán espaciados de manera uniforme. También puede almacenar 'data.year' y' data.month' con fines de etiquetado. – Plato

Respuesta

-1

Trate d3.scale.ordinal:

var y = d3.scale.ordinal() 
    .domain(yourDomain) 
    .rangeRoundBands([0, chartHeight], 0.2); 

Tweek parámetro 0,2.

+1

El OP necesita las características de una escala de tiempo. La escala ordinal no lo cortará. Por cierto, .rangeRoundBands no está disponible para D3.Scale.TimeScale. – ninjaPixel

1

Tuve el mismo problema, terminé aceptando que algunos meses son más largos que otros y ajustando el ancho de la barra de columnas para que el espacio entre barras permanezca constante. Así ajustar la función barPath en la página principal de demostración crossfilter (http://square.github.com/crossfilter/ - utiliza d3) Tengo algo como esto:

var colWidth = Math.floor(x.range()[1]/groups.length) - 1;//9; 
if (i < n - 1) { 
    //If there will be column on the right, end this column one pixel to the left 
     var nextX = x(groups[i+1].key) 
     colWidth = nextX - x(d.key) - 1; 
} 
path.push("M", x(d.key), ",", height, "V", yVal, "h",colWidth,"V", height); 
9

Se pueden combinar las escalas ordinales y hora:

// Use this to draw x axis 
var xScaleDate = d3.time.scale() 
    .domain(d3.extent(thisstat, function(d) { return d.date; })) 
    .range([0, width - margin.left - margin.right]); 

// Add an ordinal scale 
var ordinalXScale = d3.scale.ordinal() 
    .domain(d3.map(thisstat, function(d) { return d.date; })) 
    .rangeBands([0, width], 0.4, 0); 

// Now you can use both of them to space columns evenly: 
columnGroup.enter() 
    .append("rect") 
    .attr("class", "column") 
    .attr("width", ordinalXScale.rangeBand()) 
    .attr("height", function (d) { 
     return height - yScale(d.value); 
    }) 
    .attr("x", function (d) { 
     return xScaleDate(d.date); 
    }) 
    .attr("y", function (d){ 
     return yScale(d.value); 
    }); 

he creado un ejemplo hace un tiempo para demostrar este enfoque: http://codepen.io/coquin/pen/BNpQoO