Abhishek Mukherjee Abhishek Mukherjee - 11 days ago 9
Javascript Question

d3 - how to show duration interval instead of tickValues

Let's consider a horizontal bar chart as shown in the attached photo. I need to show the duration of each segment along with the x-axis. I am able to show the tick values using d3.svg.axis().tickValues(vals). But I need to show the duration in between two ticks. Can anyone help me to achieve this using d3?
enter image description here
Thanks in advance.

Answer

Here is my solution. I'm using D3 version 3 (because you wrote d3.svg.axis() in your question) and a linear scale, just to show you the principle. You can easily change it to a time scale.

Given this data:

var data = [0, 10, 40, 45, 85, 100];

We're gonna plot the differences between the ticks, i.e.: 10, 30, 5, 40 and 15.

The first step is setting the scale:

var scale = d3.scale.linear()
    .domain(d3.extent(data))
    .range([margin, w - margin]);

Then, in the axis generator, we set the ticks to match the data with:

.tickValues(data)

And we calculate the correct numbers with:

.tickFormat(function(d,i){
    if(i>0){
        return data[i] - data[i-1];
    } else { return ""};
});

The last step is translating the text to the middle position:

var ticks = d3.selectAll(".tick text").each(function(d, i) {
    d3.select(this).attr("transform", function() {
        if (i > 0) {
            return "translate(" + (-scale(data[i] - data[i - 1]) / 2 + margin/2) + ",0)";
        }
    })
})

Check the demo:

var w = 500,
    h = 100;
var svg = d3.select("body")
    .append("svg")
    .attr("width", w)
    .attr("height", h);

var data = [0, 10, 40, 45, 85, 100];

var margin = 20;

var scale = d3.scale.linear()
    .domain(d3.extent(data))
    .range([margin, w - margin]);

var colors = d3.scale.category10();

var rects = svg.selectAll(".rects")
	.data(data)
	.enter()
	.append("rect");
	
rects.attr("y", 10)
	.attr("height", 35)
	.attr("fill", (d,i)=> colors(i))
	.attr("x", d=>scale(d))
	.attr("width", (d,i)=> {
		return scale(data[i+1] - data[i]) - margin
	});

var axis = d3.svg.axis()
    .scale(scale)
    .orient("bottom")
    .tickValues(data)
    .tickFormat(function(d, i) {
        if (i > 0) {
            return data[i] - data[i - 1];
        } else {
            return ""
        };
    });

var gX = svg.append("g")
    .attr("transform", "translate(0,50)")
    .attr("class", "axis")
    .call(axis);

var ticks = d3.selectAll(".tick text").each(function(d, i) {
    d3.select(this).attr("transform", function() {
        if (i > 0) {
            return "translate(" + (-scale(data[i] - data[i - 1]) / 2 + margin / 2) + ",0)";
        }
    })
})
.axis path,
.axis line {
    fill: none;
    stroke: black;
    shape-rendering: crispEdges;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>