Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

D3 time scale axis ticks are irregular on year boundaries

Tags:

d3.js

UPDATE: The bl.ocks.org example has been updated with the solution.

Is it possible to make the default tick generator for a time scale axis ignore month and year boundaries when calculating tick positions?

As seen in this bl.ocks.org example, when a D3 time scale axis with day ticks spans the end of a year, the default tick generator sometimes draws ticks with irregular spacing. This code (also in the gist above) result in an axis with ticks spaced every two days except for December 31 and January 1, which are both drawn, resulting in an irregular appearance. I've highlighted the undesirable tick labels in red.

<!DOCTYPE html>
<meta charset="utf-8">
<style>
  p { width: 600px; margin-bottom: 30px; }
  .chart { shape-rendering: crispEdges; }
  .axis text { font: 10px sans-serif; }
  .axis line, .axis path { fill: none; stroke: black; }
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>

var start_date = "2013-12-21T00:00:00Z",
    end_date   = "2014-01-07T00:00:00Z",
    iso        = d3.time.format.iso,
    t1         = iso.parse(start_date),
    t2         = iso.parse(end_date),

var margin = {top: 0, right: 10, bottom: 20, left: 10},
    width  = 600 - margin.left - margin.right,
    height = 100 - margin.top - margin.bottom;

var x = d3.time.scale()
    .domain([t1, t2])
    .range([0, width])

var xAxis = d3.svg.axis()
    .scale(x)

var svg = d3.select("body").append("svg")
    .attr("class", "chart")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

svg.append('g')
    .attr('class', 'x axis')
    .call(xAxis)
  .selectAll('text')
    .attr('fill', function(d) { if(is_problematic(d)) { return "red"; } })

function is_problematic(d) {
  return ((d.getDate() == 31) || (d.getDate() == 1));
}
like image 701
Ben Kimball Avatar asked Nov 02 '22 06:11

Ben Kimball


1 Answers

If you explicitly set the tick values, you'll avoid the weird end of the year rounding issue:

var xAxis = d3.svg.axis()
    .scale(x)
    .tickValues(d3.time.days(t1, t2).filter(function(d, i){ return !(i % 2); }))

fixed

like image 94
Adam Pearce Avatar answered Dec 06 '22 04:12

Adam Pearce