D3.js – barres uniformément espacées sur une échelle de temps

Je crée un diagramme de barre dans d3.js dans lequel chaque barre représente des cas de tuberculose totale pendant un mois. Les données consistent essentiellement en une date (initialement des chaînes en% Y-% m format, mais analysées à l'aide de d3.time.format.parse) et un nombre entier. J'aimerais que les étiquettes des axes soient relativement flexibles (montrent uniquement les limites de l'année, l'étiquette chaque mois, etc.), mais j'aimerais également que les barres soient espacées de façon égale.

Je peux obtenir un étiquetage flexible de l'axe lorsque j'utilise une échelle de date:

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

… mais les barres ne sont pas uniformément espacées en raison d'un nombre variable de jours par mois (par exemple, février et mars sont sensiblement plus rapprochés que d'autres mois). Je peux obtenir des barres uniformément espacées à l'aide d'une échelle linéaire:

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

… mais je ne peux pas comprendre comment puis-je avoir des étiquettes d'axe basées sur la date. J'ai essayé d'utiliser les deux échelles simultanément et ne générant qu'un axe de xScaleDate , juste pour voir ce qui se passerait, mais les balances ne s'harmonisent pas parfaitement.

Y a-t-il un moyen simple d'y parvenir?

Vous pouvez combiner des échelles ordinales et temporelles:

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

J'ai créé un exemple il y a quelque temps pour démontrer cette approche: http://codepen.io/coquin/pen/BNpQoO

J'ai eu le même problème, j'ai fini par accepter que certains mois sont plus longs que d'autres et que l'on ajuste la largeur de la barre de colonne afin que l'écart entre les barres reste constant. Réglage de la fonction barPath dans la démo de la page d'accueil du crossfilter (http://square.github.com/crossfilter/ – utilise d3) J'ai obtenu quelque chose comme ceci:

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

Essayez d3.scale.ordinal :

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

Tweek 0.2 paramètre.