Abhishek Mukherjee
Abhishek Mukherjee

Reputation: 361

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.

Upvotes: 1

Views: 88

Answers (1)

Gerardo Furtado
Gerardo Furtado

Reputation: 102219

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>

Upvotes: 1

Related Questions