d3 labelled horizontal chart with labels and animation











up vote
0
down vote

favorite












I am working on a d3js horizontal chart - the designers are specific in having the labels this way.



I've built the following - but would like to model it more on older code that had animation properties.



//current chart
https://codepen.io/anon/pen/ZmJzXZ



//static vertical chart http://jsfiddle.net/pg886/201/



//animated vertical chart http://jsfiddle.net/Qh9X5/12073/



-- d3js code



   var data = [{
"name": "Apples",
"value": 20,
},
{
"name": "Bananas",
"value": 12,
},
{
"name": "Grapes",
"value": 19,
},
{
"name": "Lemons",
"value": 5,
},
{
"name": "Limes",
"value": 16,
},
{
"name": "Oranges",
"value": 26,
},
{
"name": "Pears",
"value": 30,
}];

//sort bars based on value
data = data.sort(function (a, b) {
return d3.ascending(a.value, b.value);
})

//set up svg using margin conventions - we'll need plenty of room on the left for labels
var margin = {
top: 15,
right: 25,
bottom: 15,
left: 60
};

var width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;

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

var x = d3.scale.linear()
.range([0, width])
.domain([0, d3.max(data, function (d) {
return d.value;
})]);

var y = d3.scale.ordinal()
.rangeRoundBands([height, 0], .3)
.domain(data.map(function (d) {
return d.name;
}));

//make y axis to show bar names
var yAxis = d3.svg.axis()
.scale(y)
//no tick marks
.tickSize(0)
.orient("right");

var gy = svg.append("g")
.attr("class", "y axis")
.call(yAxis)

var bars = svg.selectAll(".bar")
.data(data)
.enter()
.append("g")
.attr("class", "bars")


//append rects
bars.append("rect")
.attr("class", "bar")
.attr("y", function (d) {
return y(d.name);
})
.attr("height", y.rangeBand())
.attr("x", 0)
.attr("width", function (d) {
return x(d.value);
});

//add a value label to the right of each bar
bars.append("text")
.attr("class", "label")
//y position of the label is halfway down the bar
.attr("y", function (d) {
return y(d.name) + y.rangeBand() / 2 + 4;
})
//x position is 3 pixels to the right of the bar
.attr("x", function (d) {
return x(d.value) + 3;
})
.text(function (d) {
return d.value;
});

var labels =
bars.append("text")
.attr("class", "labels")
.attr("y", function (d) {
return y(d.name) + y.rangeBand() / 2 - 30;
})
.attr("x", 0)
.text(function (d) {
return d.name;
});


enter image description here










share|improve this question






















  • Do you want the horizontal chart to have an initial animation on load?
    – Robert Andersson
    17 hours ago










  • yes - but also be able to animate if the data changes
    – The Old County
    17 hours ago










  • That would require a bit of refactoring, do you need to use version 3 of d3 or can you use the latest version?
    – Robert Andersson
    17 hours ago










  • it could be the later version - how does it matter?
    – The Old County
    9 hours ago










  • The d3 methods etc have slightly different names in the later version amongst other things, that's why I asked. I'll post an answer soon
    – Robert Andersson
    9 hours ago















up vote
0
down vote

favorite












I am working on a d3js horizontal chart - the designers are specific in having the labels this way.



I've built the following - but would like to model it more on older code that had animation properties.



//current chart
https://codepen.io/anon/pen/ZmJzXZ



//static vertical chart http://jsfiddle.net/pg886/201/



//animated vertical chart http://jsfiddle.net/Qh9X5/12073/



-- d3js code



   var data = [{
"name": "Apples",
"value": 20,
},
{
"name": "Bananas",
"value": 12,
},
{
"name": "Grapes",
"value": 19,
},
{
"name": "Lemons",
"value": 5,
},
{
"name": "Limes",
"value": 16,
},
{
"name": "Oranges",
"value": 26,
},
{
"name": "Pears",
"value": 30,
}];

//sort bars based on value
data = data.sort(function (a, b) {
return d3.ascending(a.value, b.value);
})

//set up svg using margin conventions - we'll need plenty of room on the left for labels
var margin = {
top: 15,
right: 25,
bottom: 15,
left: 60
};

var width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;

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

var x = d3.scale.linear()
.range([0, width])
.domain([0, d3.max(data, function (d) {
return d.value;
})]);

var y = d3.scale.ordinal()
.rangeRoundBands([height, 0], .3)
.domain(data.map(function (d) {
return d.name;
}));

//make y axis to show bar names
var yAxis = d3.svg.axis()
.scale(y)
//no tick marks
.tickSize(0)
.orient("right");

var gy = svg.append("g")
.attr("class", "y axis")
.call(yAxis)

var bars = svg.selectAll(".bar")
.data(data)
.enter()
.append("g")
.attr("class", "bars")


//append rects
bars.append("rect")
.attr("class", "bar")
.attr("y", function (d) {
return y(d.name);
})
.attr("height", y.rangeBand())
.attr("x", 0)
.attr("width", function (d) {
return x(d.value);
});

//add a value label to the right of each bar
bars.append("text")
.attr("class", "label")
//y position of the label is halfway down the bar
.attr("y", function (d) {
return y(d.name) + y.rangeBand() / 2 + 4;
})
//x position is 3 pixels to the right of the bar
.attr("x", function (d) {
return x(d.value) + 3;
})
.text(function (d) {
return d.value;
});

var labels =
bars.append("text")
.attr("class", "labels")
.attr("y", function (d) {
return y(d.name) + y.rangeBand() / 2 - 30;
})
.attr("x", 0)
.text(function (d) {
return d.name;
});


enter image description here










share|improve this question






















  • Do you want the horizontal chart to have an initial animation on load?
    – Robert Andersson
    17 hours ago










  • yes - but also be able to animate if the data changes
    – The Old County
    17 hours ago










  • That would require a bit of refactoring, do you need to use version 3 of d3 or can you use the latest version?
    – Robert Andersson
    17 hours ago










  • it could be the later version - how does it matter?
    – The Old County
    9 hours ago










  • The d3 methods etc have slightly different names in the later version amongst other things, that's why I asked. I'll post an answer soon
    – Robert Andersson
    9 hours ago













up vote
0
down vote

favorite









up vote
0
down vote

favorite











I am working on a d3js horizontal chart - the designers are specific in having the labels this way.



I've built the following - but would like to model it more on older code that had animation properties.



//current chart
https://codepen.io/anon/pen/ZmJzXZ



//static vertical chart http://jsfiddle.net/pg886/201/



//animated vertical chart http://jsfiddle.net/Qh9X5/12073/



-- d3js code



   var data = [{
"name": "Apples",
"value": 20,
},
{
"name": "Bananas",
"value": 12,
},
{
"name": "Grapes",
"value": 19,
},
{
"name": "Lemons",
"value": 5,
},
{
"name": "Limes",
"value": 16,
},
{
"name": "Oranges",
"value": 26,
},
{
"name": "Pears",
"value": 30,
}];

//sort bars based on value
data = data.sort(function (a, b) {
return d3.ascending(a.value, b.value);
})

//set up svg using margin conventions - we'll need plenty of room on the left for labels
var margin = {
top: 15,
right: 25,
bottom: 15,
left: 60
};

var width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;

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

var x = d3.scale.linear()
.range([0, width])
.domain([0, d3.max(data, function (d) {
return d.value;
})]);

var y = d3.scale.ordinal()
.rangeRoundBands([height, 0], .3)
.domain(data.map(function (d) {
return d.name;
}));

//make y axis to show bar names
var yAxis = d3.svg.axis()
.scale(y)
//no tick marks
.tickSize(0)
.orient("right");

var gy = svg.append("g")
.attr("class", "y axis")
.call(yAxis)

var bars = svg.selectAll(".bar")
.data(data)
.enter()
.append("g")
.attr("class", "bars")


//append rects
bars.append("rect")
.attr("class", "bar")
.attr("y", function (d) {
return y(d.name);
})
.attr("height", y.rangeBand())
.attr("x", 0)
.attr("width", function (d) {
return x(d.value);
});

//add a value label to the right of each bar
bars.append("text")
.attr("class", "label")
//y position of the label is halfway down the bar
.attr("y", function (d) {
return y(d.name) + y.rangeBand() / 2 + 4;
})
//x position is 3 pixels to the right of the bar
.attr("x", function (d) {
return x(d.value) + 3;
})
.text(function (d) {
return d.value;
});

var labels =
bars.append("text")
.attr("class", "labels")
.attr("y", function (d) {
return y(d.name) + y.rangeBand() / 2 - 30;
})
.attr("x", 0)
.text(function (d) {
return d.name;
});


enter image description here










share|improve this question













I am working on a d3js horizontal chart - the designers are specific in having the labels this way.



I've built the following - but would like to model it more on older code that had animation properties.



//current chart
https://codepen.io/anon/pen/ZmJzXZ



//static vertical chart http://jsfiddle.net/pg886/201/



//animated vertical chart http://jsfiddle.net/Qh9X5/12073/



-- d3js code



   var data = [{
"name": "Apples",
"value": 20,
},
{
"name": "Bananas",
"value": 12,
},
{
"name": "Grapes",
"value": 19,
},
{
"name": "Lemons",
"value": 5,
},
{
"name": "Limes",
"value": 16,
},
{
"name": "Oranges",
"value": 26,
},
{
"name": "Pears",
"value": 30,
}];

//sort bars based on value
data = data.sort(function (a, b) {
return d3.ascending(a.value, b.value);
})

//set up svg using margin conventions - we'll need plenty of room on the left for labels
var margin = {
top: 15,
right: 25,
bottom: 15,
left: 60
};

var width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;

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

var x = d3.scale.linear()
.range([0, width])
.domain([0, d3.max(data, function (d) {
return d.value;
})]);

var y = d3.scale.ordinal()
.rangeRoundBands([height, 0], .3)
.domain(data.map(function (d) {
return d.name;
}));

//make y axis to show bar names
var yAxis = d3.svg.axis()
.scale(y)
//no tick marks
.tickSize(0)
.orient("right");

var gy = svg.append("g")
.attr("class", "y axis")
.call(yAxis)

var bars = svg.selectAll(".bar")
.data(data)
.enter()
.append("g")
.attr("class", "bars")


//append rects
bars.append("rect")
.attr("class", "bar")
.attr("y", function (d) {
return y(d.name);
})
.attr("height", y.rangeBand())
.attr("x", 0)
.attr("width", function (d) {
return x(d.value);
});

//add a value label to the right of each bar
bars.append("text")
.attr("class", "label")
//y position of the label is halfway down the bar
.attr("y", function (d) {
return y(d.name) + y.rangeBand() / 2 + 4;
})
//x position is 3 pixels to the right of the bar
.attr("x", function (d) {
return x(d.value) + 3;
})
.text(function (d) {
return d.value;
});

var labels =
bars.append("text")
.attr("class", "labels")
.attr("y", function (d) {
return y(d.name) + y.rangeBand() / 2 - 30;
})
.attr("x", 0)
.text(function (d) {
return d.name;
});


enter image description here







d3.js






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked 17 hours ago









The Old County

5911851




5911851












  • Do you want the horizontal chart to have an initial animation on load?
    – Robert Andersson
    17 hours ago










  • yes - but also be able to animate if the data changes
    – The Old County
    17 hours ago










  • That would require a bit of refactoring, do you need to use version 3 of d3 or can you use the latest version?
    – Robert Andersson
    17 hours ago










  • it could be the later version - how does it matter?
    – The Old County
    9 hours ago










  • The d3 methods etc have slightly different names in the later version amongst other things, that's why I asked. I'll post an answer soon
    – Robert Andersson
    9 hours ago


















  • Do you want the horizontal chart to have an initial animation on load?
    – Robert Andersson
    17 hours ago










  • yes - but also be able to animate if the data changes
    – The Old County
    17 hours ago










  • That would require a bit of refactoring, do you need to use version 3 of d3 or can you use the latest version?
    – Robert Andersson
    17 hours ago










  • it could be the later version - how does it matter?
    – The Old County
    9 hours ago










  • The d3 methods etc have slightly different names in the later version amongst other things, that's why I asked. I'll post an answer soon
    – Robert Andersson
    9 hours ago
















Do you want the horizontal chart to have an initial animation on load?
– Robert Andersson
17 hours ago




Do you want the horizontal chart to have an initial animation on load?
– Robert Andersson
17 hours ago












yes - but also be able to animate if the data changes
– The Old County
17 hours ago




yes - but also be able to animate if the data changes
– The Old County
17 hours ago












That would require a bit of refactoring, do you need to use version 3 of d3 or can you use the latest version?
– Robert Andersson
17 hours ago




That would require a bit of refactoring, do you need to use version 3 of d3 or can you use the latest version?
– Robert Andersson
17 hours ago












it could be the later version - how does it matter?
– The Old County
9 hours ago




it could be the later version - how does it matter?
– The Old County
9 hours ago












The d3 methods etc have slightly different names in the later version amongst other things, that's why I asked. I'll post an answer soon
– Robert Andersson
9 hours ago




The d3 methods etc have slightly different names in the later version amongst other things, that's why I asked. I'll post an answer soon
– Robert Andersson
9 hours ago












1 Answer
1






active

oldest

votes

















up vote
0
down vote













I had a similar chart that I've made a few modifications to that might fill your requierments, so I'll be basing my answer of my own code.



I'll just go through the most relevant part of the question and you can just have a look at the code and hopefully figure out how it works yourself.



The inital animation works exactly the same way as in the third link you posted:



.transition().duration(speed)
.delay((_, i) => delay * i)


we set a delay so that each bar appear one at a time.



I've also set it up so that you can change the data using the d3js update pattern.



    var bar = svg.selectAll(".bar")
.data(data, d => d.name)

bar.exit().remove();

bar.enter().insert("g", ".y-axis").append("rect")
.attr("class", "bar")
.attr("fill", "#ccc")
.attr("x", x(0))
.attr("y", d => y(d.name))
.attr("height", y.bandwidth())
.merge(bar)
.transition().duration(speed)
.delay((_, i) => delay * i)
.attr("y", d => y(d.name))
.attr("width", d => x(d.value) - x(0));


Since you didn't specify how you want to update the new data it's just a year filter for now.



Here's all the code:






var init = [
{"year": "2017", "name": "Apples", "value": 20},
{"year": "2017", "name": "Bananas","value": 12},
{"year": "2017", "name": "Grapes", "value": 19},
{"year": "2017", "name": "Lemons", "value": 5},
{"year": "2017", "name": "Limes", "value": 16},
{"year": "2017", "name": "Oranges", "value": 26},
{"year": "2017", "name": "Pears","value": 30},
{"year": "2018", "name": "Apples", "value": 10},
{"year": "2018", "name": "Bananas","value": 42},
{"year": "2018", "name": "Grapes", "value": 69},
{"year": "2018", "name": "Lemons", "value": 15},
{"year": "2018", "name": "Limes", "value": 26},
{"year": "2018", "name": "Oranges", "value": 36},
{"year": "2018", "name": "Pears","value": 20}
];

chart(init)

function chart(result) {

var format = d3.format(",.0f")

var years = [...new Set(result.map(d => d.year))]
var fruit = [...new Set(result.map(d => d.name))]

var options = d3.select("#year").selectAll("option")
.data(years)
.enter().append("option")
.text(d => d)

var svg = d3.select("#graphic"),
margin = {top: 25, bottom: 10, left: 50, right: 45},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom;

var x = d3.scaleLinear()
.range([margin.left, width - margin.right])

var y = d3.scaleBand()
.range([margin.top, height - margin.bottom])
.padding(0.1)
.paddingOuter(0.5)
.paddingInner(0.5)

var xAxis = svg.append("g")
.attr("class", "x-axis")
.attr("transform", `translate(0,${margin.top})`)

var yAxis = svg.append("g")
.attr("class", "y-axis")
.attr("transform", `translate(${margin.left},0)`)

update(d3.select("#year").property("value"), 750, 250)

function update(input, speed, delay) {

var data = result.filter(f => f.year == input)

var sum = d3.sum(data, d => d.value)

x.domain([0, d3.max(data, d => d.value)]).nice()

svg.selectAll(".x-axis").transition().duration(speed)
.call(d3.axisTop(x).tickSizeOuter(0));

data.sort((a, b) => b.value - a.value)

y.domain(data.map(d => d.name))

svg.selectAll(".y-axis").transition().duration(speed)
.call(d3.axisLeft(y));

yAxis.selectAll("text").remove()
yAxis.selectAll("line").remove()

var bar = svg.selectAll(".bar")
.data(data, d => d.name)

bar.exit().remove();

bar.enter().insert("g", ".y-axis").append("rect")
.attr("class", "bar")
.attr("fill", "#ccc")
.attr("x", x(0))
.attr("y", d => y(d.name))
.attr("height", y.bandwidth())
.merge(bar)
.transition().duration(speed)
.delay((_, i) => delay * i)
.attr("y", d => y(d.name))
.attr("width", d => x(d.value) - x(0));

var value = svg.selectAll(".value")
.data(data, d => d.name)

value.exit().remove();

value.enter().append("text")
.attr("class", "value")
.attr("opacity", 0)
.attr("dy", 4)
.attr("y", d => y(d.name) + y.bandwidth() / 2)
.merge(value)
.transition().duration(speed)
.delay((_, i) => delay * i)
.attr("opacity", 1)
.attr("y", d => y(d.name) + y.bandwidth() / 2)
.attr("x", d => x(d.value) + 5)
.text(d => format((d.value / sum) * 100) + " %")

var name = svg.selectAll(".name")
.data(data, d => d.name)

name.exit().remove();

name.enter().append("text")
.attr("class", "name")
.attr("opacity", 0)
.attr("dy", -5)
.attr("y", d => y(d.name))
.merge(name)
.transition().duration(speed)
.delay((_, i) => delay * i)
.attr("opacity", 1)
.attr("y", d => y(d.name))
.attr("x", d => x(0) + 5)
.text(d => d.name)
}

var select = d3.select("#year")
.style("border-radius", "5px")
.on("change", function() {
update(this.value, 750, 0)
})
}

body {
margin: auto;
width: 650px;
font: 12px arial;
}

<script src="https://d3js.org/d3.v5.min.js"></script>
<svg id="graphic" width="600" height="380"></svg><br>

Choose year:
<select id="year"></select>








share|improve this answer





















    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














     

    draft saved


    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53371846%2fd3-labelled-horizontal-chart-with-labels-and-animation%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    0
    down vote













    I had a similar chart that I've made a few modifications to that might fill your requierments, so I'll be basing my answer of my own code.



    I'll just go through the most relevant part of the question and you can just have a look at the code and hopefully figure out how it works yourself.



    The inital animation works exactly the same way as in the third link you posted:



    .transition().duration(speed)
    .delay((_, i) => delay * i)


    we set a delay so that each bar appear one at a time.



    I've also set it up so that you can change the data using the d3js update pattern.



        var bar = svg.selectAll(".bar")
    .data(data, d => d.name)

    bar.exit().remove();

    bar.enter().insert("g", ".y-axis").append("rect")
    .attr("class", "bar")
    .attr("fill", "#ccc")
    .attr("x", x(0))
    .attr("y", d => y(d.name))
    .attr("height", y.bandwidth())
    .merge(bar)
    .transition().duration(speed)
    .delay((_, i) => delay * i)
    .attr("y", d => y(d.name))
    .attr("width", d => x(d.value) - x(0));


    Since you didn't specify how you want to update the new data it's just a year filter for now.



    Here's all the code:






    var init = [
    {"year": "2017", "name": "Apples", "value": 20},
    {"year": "2017", "name": "Bananas","value": 12},
    {"year": "2017", "name": "Grapes", "value": 19},
    {"year": "2017", "name": "Lemons", "value": 5},
    {"year": "2017", "name": "Limes", "value": 16},
    {"year": "2017", "name": "Oranges", "value": 26},
    {"year": "2017", "name": "Pears","value": 30},
    {"year": "2018", "name": "Apples", "value": 10},
    {"year": "2018", "name": "Bananas","value": 42},
    {"year": "2018", "name": "Grapes", "value": 69},
    {"year": "2018", "name": "Lemons", "value": 15},
    {"year": "2018", "name": "Limes", "value": 26},
    {"year": "2018", "name": "Oranges", "value": 36},
    {"year": "2018", "name": "Pears","value": 20}
    ];

    chart(init)

    function chart(result) {

    var format = d3.format(",.0f")

    var years = [...new Set(result.map(d => d.year))]
    var fruit = [...new Set(result.map(d => d.name))]

    var options = d3.select("#year").selectAll("option")
    .data(years)
    .enter().append("option")
    .text(d => d)

    var svg = d3.select("#graphic"),
    margin = {top: 25, bottom: 10, left: 50, right: 45},
    width = +svg.attr("width") - margin.left - margin.right,
    height = +svg.attr("height") - margin.top - margin.bottom;

    var x = d3.scaleLinear()
    .range([margin.left, width - margin.right])

    var y = d3.scaleBand()
    .range([margin.top, height - margin.bottom])
    .padding(0.1)
    .paddingOuter(0.5)
    .paddingInner(0.5)

    var xAxis = svg.append("g")
    .attr("class", "x-axis")
    .attr("transform", `translate(0,${margin.top})`)

    var yAxis = svg.append("g")
    .attr("class", "y-axis")
    .attr("transform", `translate(${margin.left},0)`)

    update(d3.select("#year").property("value"), 750, 250)

    function update(input, speed, delay) {

    var data = result.filter(f => f.year == input)

    var sum = d3.sum(data, d => d.value)

    x.domain([0, d3.max(data, d => d.value)]).nice()

    svg.selectAll(".x-axis").transition().duration(speed)
    .call(d3.axisTop(x).tickSizeOuter(0));

    data.sort((a, b) => b.value - a.value)

    y.domain(data.map(d => d.name))

    svg.selectAll(".y-axis").transition().duration(speed)
    .call(d3.axisLeft(y));

    yAxis.selectAll("text").remove()
    yAxis.selectAll("line").remove()

    var bar = svg.selectAll(".bar")
    .data(data, d => d.name)

    bar.exit().remove();

    bar.enter().insert("g", ".y-axis").append("rect")
    .attr("class", "bar")
    .attr("fill", "#ccc")
    .attr("x", x(0))
    .attr("y", d => y(d.name))
    .attr("height", y.bandwidth())
    .merge(bar)
    .transition().duration(speed)
    .delay((_, i) => delay * i)
    .attr("y", d => y(d.name))
    .attr("width", d => x(d.value) - x(0));

    var value = svg.selectAll(".value")
    .data(data, d => d.name)

    value.exit().remove();

    value.enter().append("text")
    .attr("class", "value")
    .attr("opacity", 0)
    .attr("dy", 4)
    .attr("y", d => y(d.name) + y.bandwidth() / 2)
    .merge(value)
    .transition().duration(speed)
    .delay((_, i) => delay * i)
    .attr("opacity", 1)
    .attr("y", d => y(d.name) + y.bandwidth() / 2)
    .attr("x", d => x(d.value) + 5)
    .text(d => format((d.value / sum) * 100) + " %")

    var name = svg.selectAll(".name")
    .data(data, d => d.name)

    name.exit().remove();

    name.enter().append("text")
    .attr("class", "name")
    .attr("opacity", 0)
    .attr("dy", -5)
    .attr("y", d => y(d.name))
    .merge(name)
    .transition().duration(speed)
    .delay((_, i) => delay * i)
    .attr("opacity", 1)
    .attr("y", d => y(d.name))
    .attr("x", d => x(0) + 5)
    .text(d => d.name)
    }

    var select = d3.select("#year")
    .style("border-radius", "5px")
    .on("change", function() {
    update(this.value, 750, 0)
    })
    }

    body {
    margin: auto;
    width: 650px;
    font: 12px arial;
    }

    <script src="https://d3js.org/d3.v5.min.js"></script>
    <svg id="graphic" width="600" height="380"></svg><br>

    Choose year:
    <select id="year"></select>








    share|improve this answer

























      up vote
      0
      down vote













      I had a similar chart that I've made a few modifications to that might fill your requierments, so I'll be basing my answer of my own code.



      I'll just go through the most relevant part of the question and you can just have a look at the code and hopefully figure out how it works yourself.



      The inital animation works exactly the same way as in the third link you posted:



      .transition().duration(speed)
      .delay((_, i) => delay * i)


      we set a delay so that each bar appear one at a time.



      I've also set it up so that you can change the data using the d3js update pattern.



          var bar = svg.selectAll(".bar")
      .data(data, d => d.name)

      bar.exit().remove();

      bar.enter().insert("g", ".y-axis").append("rect")
      .attr("class", "bar")
      .attr("fill", "#ccc")
      .attr("x", x(0))
      .attr("y", d => y(d.name))
      .attr("height", y.bandwidth())
      .merge(bar)
      .transition().duration(speed)
      .delay((_, i) => delay * i)
      .attr("y", d => y(d.name))
      .attr("width", d => x(d.value) - x(0));


      Since you didn't specify how you want to update the new data it's just a year filter for now.



      Here's all the code:






      var init = [
      {"year": "2017", "name": "Apples", "value": 20},
      {"year": "2017", "name": "Bananas","value": 12},
      {"year": "2017", "name": "Grapes", "value": 19},
      {"year": "2017", "name": "Lemons", "value": 5},
      {"year": "2017", "name": "Limes", "value": 16},
      {"year": "2017", "name": "Oranges", "value": 26},
      {"year": "2017", "name": "Pears","value": 30},
      {"year": "2018", "name": "Apples", "value": 10},
      {"year": "2018", "name": "Bananas","value": 42},
      {"year": "2018", "name": "Grapes", "value": 69},
      {"year": "2018", "name": "Lemons", "value": 15},
      {"year": "2018", "name": "Limes", "value": 26},
      {"year": "2018", "name": "Oranges", "value": 36},
      {"year": "2018", "name": "Pears","value": 20}
      ];

      chart(init)

      function chart(result) {

      var format = d3.format(",.0f")

      var years = [...new Set(result.map(d => d.year))]
      var fruit = [...new Set(result.map(d => d.name))]

      var options = d3.select("#year").selectAll("option")
      .data(years)
      .enter().append("option")
      .text(d => d)

      var svg = d3.select("#graphic"),
      margin = {top: 25, bottom: 10, left: 50, right: 45},
      width = +svg.attr("width") - margin.left - margin.right,
      height = +svg.attr("height") - margin.top - margin.bottom;

      var x = d3.scaleLinear()
      .range([margin.left, width - margin.right])

      var y = d3.scaleBand()
      .range([margin.top, height - margin.bottom])
      .padding(0.1)
      .paddingOuter(0.5)
      .paddingInner(0.5)

      var xAxis = svg.append("g")
      .attr("class", "x-axis")
      .attr("transform", `translate(0,${margin.top})`)

      var yAxis = svg.append("g")
      .attr("class", "y-axis")
      .attr("transform", `translate(${margin.left},0)`)

      update(d3.select("#year").property("value"), 750, 250)

      function update(input, speed, delay) {

      var data = result.filter(f => f.year == input)

      var sum = d3.sum(data, d => d.value)

      x.domain([0, d3.max(data, d => d.value)]).nice()

      svg.selectAll(".x-axis").transition().duration(speed)
      .call(d3.axisTop(x).tickSizeOuter(0));

      data.sort((a, b) => b.value - a.value)

      y.domain(data.map(d => d.name))

      svg.selectAll(".y-axis").transition().duration(speed)
      .call(d3.axisLeft(y));

      yAxis.selectAll("text").remove()
      yAxis.selectAll("line").remove()

      var bar = svg.selectAll(".bar")
      .data(data, d => d.name)

      bar.exit().remove();

      bar.enter().insert("g", ".y-axis").append("rect")
      .attr("class", "bar")
      .attr("fill", "#ccc")
      .attr("x", x(0))
      .attr("y", d => y(d.name))
      .attr("height", y.bandwidth())
      .merge(bar)
      .transition().duration(speed)
      .delay((_, i) => delay * i)
      .attr("y", d => y(d.name))
      .attr("width", d => x(d.value) - x(0));

      var value = svg.selectAll(".value")
      .data(data, d => d.name)

      value.exit().remove();

      value.enter().append("text")
      .attr("class", "value")
      .attr("opacity", 0)
      .attr("dy", 4)
      .attr("y", d => y(d.name) + y.bandwidth() / 2)
      .merge(value)
      .transition().duration(speed)
      .delay((_, i) => delay * i)
      .attr("opacity", 1)
      .attr("y", d => y(d.name) + y.bandwidth() / 2)
      .attr("x", d => x(d.value) + 5)
      .text(d => format((d.value / sum) * 100) + " %")

      var name = svg.selectAll(".name")
      .data(data, d => d.name)

      name.exit().remove();

      name.enter().append("text")
      .attr("class", "name")
      .attr("opacity", 0)
      .attr("dy", -5)
      .attr("y", d => y(d.name))
      .merge(name)
      .transition().duration(speed)
      .delay((_, i) => delay * i)
      .attr("opacity", 1)
      .attr("y", d => y(d.name))
      .attr("x", d => x(0) + 5)
      .text(d => d.name)
      }

      var select = d3.select("#year")
      .style("border-radius", "5px")
      .on("change", function() {
      update(this.value, 750, 0)
      })
      }

      body {
      margin: auto;
      width: 650px;
      font: 12px arial;
      }

      <script src="https://d3js.org/d3.v5.min.js"></script>
      <svg id="graphic" width="600" height="380"></svg><br>

      Choose year:
      <select id="year"></select>








      share|improve this answer























        up vote
        0
        down vote










        up vote
        0
        down vote









        I had a similar chart that I've made a few modifications to that might fill your requierments, so I'll be basing my answer of my own code.



        I'll just go through the most relevant part of the question and you can just have a look at the code and hopefully figure out how it works yourself.



        The inital animation works exactly the same way as in the third link you posted:



        .transition().duration(speed)
        .delay((_, i) => delay * i)


        we set a delay so that each bar appear one at a time.



        I've also set it up so that you can change the data using the d3js update pattern.



            var bar = svg.selectAll(".bar")
        .data(data, d => d.name)

        bar.exit().remove();

        bar.enter().insert("g", ".y-axis").append("rect")
        .attr("class", "bar")
        .attr("fill", "#ccc")
        .attr("x", x(0))
        .attr("y", d => y(d.name))
        .attr("height", y.bandwidth())
        .merge(bar)
        .transition().duration(speed)
        .delay((_, i) => delay * i)
        .attr("y", d => y(d.name))
        .attr("width", d => x(d.value) - x(0));


        Since you didn't specify how you want to update the new data it's just a year filter for now.



        Here's all the code:






        var init = [
        {"year": "2017", "name": "Apples", "value": 20},
        {"year": "2017", "name": "Bananas","value": 12},
        {"year": "2017", "name": "Grapes", "value": 19},
        {"year": "2017", "name": "Lemons", "value": 5},
        {"year": "2017", "name": "Limes", "value": 16},
        {"year": "2017", "name": "Oranges", "value": 26},
        {"year": "2017", "name": "Pears","value": 30},
        {"year": "2018", "name": "Apples", "value": 10},
        {"year": "2018", "name": "Bananas","value": 42},
        {"year": "2018", "name": "Grapes", "value": 69},
        {"year": "2018", "name": "Lemons", "value": 15},
        {"year": "2018", "name": "Limes", "value": 26},
        {"year": "2018", "name": "Oranges", "value": 36},
        {"year": "2018", "name": "Pears","value": 20}
        ];

        chart(init)

        function chart(result) {

        var format = d3.format(",.0f")

        var years = [...new Set(result.map(d => d.year))]
        var fruit = [...new Set(result.map(d => d.name))]

        var options = d3.select("#year").selectAll("option")
        .data(years)
        .enter().append("option")
        .text(d => d)

        var svg = d3.select("#graphic"),
        margin = {top: 25, bottom: 10, left: 50, right: 45},
        width = +svg.attr("width") - margin.left - margin.right,
        height = +svg.attr("height") - margin.top - margin.bottom;

        var x = d3.scaleLinear()
        .range([margin.left, width - margin.right])

        var y = d3.scaleBand()
        .range([margin.top, height - margin.bottom])
        .padding(0.1)
        .paddingOuter(0.5)
        .paddingInner(0.5)

        var xAxis = svg.append("g")
        .attr("class", "x-axis")
        .attr("transform", `translate(0,${margin.top})`)

        var yAxis = svg.append("g")
        .attr("class", "y-axis")
        .attr("transform", `translate(${margin.left},0)`)

        update(d3.select("#year").property("value"), 750, 250)

        function update(input, speed, delay) {

        var data = result.filter(f => f.year == input)

        var sum = d3.sum(data, d => d.value)

        x.domain([0, d3.max(data, d => d.value)]).nice()

        svg.selectAll(".x-axis").transition().duration(speed)
        .call(d3.axisTop(x).tickSizeOuter(0));

        data.sort((a, b) => b.value - a.value)

        y.domain(data.map(d => d.name))

        svg.selectAll(".y-axis").transition().duration(speed)
        .call(d3.axisLeft(y));

        yAxis.selectAll("text").remove()
        yAxis.selectAll("line").remove()

        var bar = svg.selectAll(".bar")
        .data(data, d => d.name)

        bar.exit().remove();

        bar.enter().insert("g", ".y-axis").append("rect")
        .attr("class", "bar")
        .attr("fill", "#ccc")
        .attr("x", x(0))
        .attr("y", d => y(d.name))
        .attr("height", y.bandwidth())
        .merge(bar)
        .transition().duration(speed)
        .delay((_, i) => delay * i)
        .attr("y", d => y(d.name))
        .attr("width", d => x(d.value) - x(0));

        var value = svg.selectAll(".value")
        .data(data, d => d.name)

        value.exit().remove();

        value.enter().append("text")
        .attr("class", "value")
        .attr("opacity", 0)
        .attr("dy", 4)
        .attr("y", d => y(d.name) + y.bandwidth() / 2)
        .merge(value)
        .transition().duration(speed)
        .delay((_, i) => delay * i)
        .attr("opacity", 1)
        .attr("y", d => y(d.name) + y.bandwidth() / 2)
        .attr("x", d => x(d.value) + 5)
        .text(d => format((d.value / sum) * 100) + " %")

        var name = svg.selectAll(".name")
        .data(data, d => d.name)

        name.exit().remove();

        name.enter().append("text")
        .attr("class", "name")
        .attr("opacity", 0)
        .attr("dy", -5)
        .attr("y", d => y(d.name))
        .merge(name)
        .transition().duration(speed)
        .delay((_, i) => delay * i)
        .attr("opacity", 1)
        .attr("y", d => y(d.name))
        .attr("x", d => x(0) + 5)
        .text(d => d.name)
        }

        var select = d3.select("#year")
        .style("border-radius", "5px")
        .on("change", function() {
        update(this.value, 750, 0)
        })
        }

        body {
        margin: auto;
        width: 650px;
        font: 12px arial;
        }

        <script src="https://d3js.org/d3.v5.min.js"></script>
        <svg id="graphic" width="600" height="380"></svg><br>

        Choose year:
        <select id="year"></select>








        share|improve this answer












        I had a similar chart that I've made a few modifications to that might fill your requierments, so I'll be basing my answer of my own code.



        I'll just go through the most relevant part of the question and you can just have a look at the code and hopefully figure out how it works yourself.



        The inital animation works exactly the same way as in the third link you posted:



        .transition().duration(speed)
        .delay((_, i) => delay * i)


        we set a delay so that each bar appear one at a time.



        I've also set it up so that you can change the data using the d3js update pattern.



            var bar = svg.selectAll(".bar")
        .data(data, d => d.name)

        bar.exit().remove();

        bar.enter().insert("g", ".y-axis").append("rect")
        .attr("class", "bar")
        .attr("fill", "#ccc")
        .attr("x", x(0))
        .attr("y", d => y(d.name))
        .attr("height", y.bandwidth())
        .merge(bar)
        .transition().duration(speed)
        .delay((_, i) => delay * i)
        .attr("y", d => y(d.name))
        .attr("width", d => x(d.value) - x(0));


        Since you didn't specify how you want to update the new data it's just a year filter for now.



        Here's all the code:






        var init = [
        {"year": "2017", "name": "Apples", "value": 20},
        {"year": "2017", "name": "Bananas","value": 12},
        {"year": "2017", "name": "Grapes", "value": 19},
        {"year": "2017", "name": "Lemons", "value": 5},
        {"year": "2017", "name": "Limes", "value": 16},
        {"year": "2017", "name": "Oranges", "value": 26},
        {"year": "2017", "name": "Pears","value": 30},
        {"year": "2018", "name": "Apples", "value": 10},
        {"year": "2018", "name": "Bananas","value": 42},
        {"year": "2018", "name": "Grapes", "value": 69},
        {"year": "2018", "name": "Lemons", "value": 15},
        {"year": "2018", "name": "Limes", "value": 26},
        {"year": "2018", "name": "Oranges", "value": 36},
        {"year": "2018", "name": "Pears","value": 20}
        ];

        chart(init)

        function chart(result) {

        var format = d3.format(",.0f")

        var years = [...new Set(result.map(d => d.year))]
        var fruit = [...new Set(result.map(d => d.name))]

        var options = d3.select("#year").selectAll("option")
        .data(years)
        .enter().append("option")
        .text(d => d)

        var svg = d3.select("#graphic"),
        margin = {top: 25, bottom: 10, left: 50, right: 45},
        width = +svg.attr("width") - margin.left - margin.right,
        height = +svg.attr("height") - margin.top - margin.bottom;

        var x = d3.scaleLinear()
        .range([margin.left, width - margin.right])

        var y = d3.scaleBand()
        .range([margin.top, height - margin.bottom])
        .padding(0.1)
        .paddingOuter(0.5)
        .paddingInner(0.5)

        var xAxis = svg.append("g")
        .attr("class", "x-axis")
        .attr("transform", `translate(0,${margin.top})`)

        var yAxis = svg.append("g")
        .attr("class", "y-axis")
        .attr("transform", `translate(${margin.left},0)`)

        update(d3.select("#year").property("value"), 750, 250)

        function update(input, speed, delay) {

        var data = result.filter(f => f.year == input)

        var sum = d3.sum(data, d => d.value)

        x.domain([0, d3.max(data, d => d.value)]).nice()

        svg.selectAll(".x-axis").transition().duration(speed)
        .call(d3.axisTop(x).tickSizeOuter(0));

        data.sort((a, b) => b.value - a.value)

        y.domain(data.map(d => d.name))

        svg.selectAll(".y-axis").transition().duration(speed)
        .call(d3.axisLeft(y));

        yAxis.selectAll("text").remove()
        yAxis.selectAll("line").remove()

        var bar = svg.selectAll(".bar")
        .data(data, d => d.name)

        bar.exit().remove();

        bar.enter().insert("g", ".y-axis").append("rect")
        .attr("class", "bar")
        .attr("fill", "#ccc")
        .attr("x", x(0))
        .attr("y", d => y(d.name))
        .attr("height", y.bandwidth())
        .merge(bar)
        .transition().duration(speed)
        .delay((_, i) => delay * i)
        .attr("y", d => y(d.name))
        .attr("width", d => x(d.value) - x(0));

        var value = svg.selectAll(".value")
        .data(data, d => d.name)

        value.exit().remove();

        value.enter().append("text")
        .attr("class", "value")
        .attr("opacity", 0)
        .attr("dy", 4)
        .attr("y", d => y(d.name) + y.bandwidth() / 2)
        .merge(value)
        .transition().duration(speed)
        .delay((_, i) => delay * i)
        .attr("opacity", 1)
        .attr("y", d => y(d.name) + y.bandwidth() / 2)
        .attr("x", d => x(d.value) + 5)
        .text(d => format((d.value / sum) * 100) + " %")

        var name = svg.selectAll(".name")
        .data(data, d => d.name)

        name.exit().remove();

        name.enter().append("text")
        .attr("class", "name")
        .attr("opacity", 0)
        .attr("dy", -5)
        .attr("y", d => y(d.name))
        .merge(name)
        .transition().duration(speed)
        .delay((_, i) => delay * i)
        .attr("opacity", 1)
        .attr("y", d => y(d.name))
        .attr("x", d => x(0) + 5)
        .text(d => d.name)
        }

        var select = d3.select("#year")
        .style("border-radius", "5px")
        .on("change", function() {
        update(this.value, 750, 0)
        })
        }

        body {
        margin: auto;
        width: 650px;
        font: 12px arial;
        }

        <script src="https://d3js.org/d3.v5.min.js"></script>
        <svg id="graphic" width="600" height="380"></svg><br>

        Choose year:
        <select id="year"></select>








        var init = [
        {"year": "2017", "name": "Apples", "value": 20},
        {"year": "2017", "name": "Bananas","value": 12},
        {"year": "2017", "name": "Grapes", "value": 19},
        {"year": "2017", "name": "Lemons", "value": 5},
        {"year": "2017", "name": "Limes", "value": 16},
        {"year": "2017", "name": "Oranges", "value": 26},
        {"year": "2017", "name": "Pears","value": 30},
        {"year": "2018", "name": "Apples", "value": 10},
        {"year": "2018", "name": "Bananas","value": 42},
        {"year": "2018", "name": "Grapes", "value": 69},
        {"year": "2018", "name": "Lemons", "value": 15},
        {"year": "2018", "name": "Limes", "value": 26},
        {"year": "2018", "name": "Oranges", "value": 36},
        {"year": "2018", "name": "Pears","value": 20}
        ];

        chart(init)

        function chart(result) {

        var format = d3.format(",.0f")

        var years = [...new Set(result.map(d => d.year))]
        var fruit = [...new Set(result.map(d => d.name))]

        var options = d3.select("#year").selectAll("option")
        .data(years)
        .enter().append("option")
        .text(d => d)

        var svg = d3.select("#graphic"),
        margin = {top: 25, bottom: 10, left: 50, right: 45},
        width = +svg.attr("width") - margin.left - margin.right,
        height = +svg.attr("height") - margin.top - margin.bottom;

        var x = d3.scaleLinear()
        .range([margin.left, width - margin.right])

        var y = d3.scaleBand()
        .range([margin.top, height - margin.bottom])
        .padding(0.1)
        .paddingOuter(0.5)
        .paddingInner(0.5)

        var xAxis = svg.append("g")
        .attr("class", "x-axis")
        .attr("transform", `translate(0,${margin.top})`)

        var yAxis = svg.append("g")
        .attr("class", "y-axis")
        .attr("transform", `translate(${margin.left},0)`)

        update(d3.select("#year").property("value"), 750, 250)

        function update(input, speed, delay) {

        var data = result.filter(f => f.year == input)

        var sum = d3.sum(data, d => d.value)

        x.domain([0, d3.max(data, d => d.value)]).nice()

        svg.selectAll(".x-axis").transition().duration(speed)
        .call(d3.axisTop(x).tickSizeOuter(0));

        data.sort((a, b) => b.value - a.value)

        y.domain(data.map(d => d.name))

        svg.selectAll(".y-axis").transition().duration(speed)
        .call(d3.axisLeft(y));

        yAxis.selectAll("text").remove()
        yAxis.selectAll("line").remove()

        var bar = svg.selectAll(".bar")
        .data(data, d => d.name)

        bar.exit().remove();

        bar.enter().insert("g", ".y-axis").append("rect")
        .attr("class", "bar")
        .attr("fill", "#ccc")
        .attr("x", x(0))
        .attr("y", d => y(d.name))
        .attr("height", y.bandwidth())
        .merge(bar)
        .transition().duration(speed)
        .delay((_, i) => delay * i)
        .attr("y", d => y(d.name))
        .attr("width", d => x(d.value) - x(0));

        var value = svg.selectAll(".value")
        .data(data, d => d.name)

        value.exit().remove();

        value.enter().append("text")
        .attr("class", "value")
        .attr("opacity", 0)
        .attr("dy", 4)
        .attr("y", d => y(d.name) + y.bandwidth() / 2)
        .merge(value)
        .transition().duration(speed)
        .delay((_, i) => delay * i)
        .attr("opacity", 1)
        .attr("y", d => y(d.name) + y.bandwidth() / 2)
        .attr("x", d => x(d.value) + 5)
        .text(d => format((d.value / sum) * 100) + " %")

        var name = svg.selectAll(".name")
        .data(data, d => d.name)

        name.exit().remove();

        name.enter().append("text")
        .attr("class", "name")
        .attr("opacity", 0)
        .attr("dy", -5)
        .attr("y", d => y(d.name))
        .merge(name)
        .transition().duration(speed)
        .delay((_, i) => delay * i)
        .attr("opacity", 1)
        .attr("y", d => y(d.name))
        .attr("x", d => x(0) + 5)
        .text(d => d.name)
        }

        var select = d3.select("#year")
        .style("border-radius", "5px")
        .on("change", function() {
        update(this.value, 750, 0)
        })
        }

        body {
        margin: auto;
        width: 650px;
        font: 12px arial;
        }

        <script src="https://d3js.org/d3.v5.min.js"></script>
        <svg id="graphic" width="600" height="380"></svg><br>

        Choose year:
        <select id="year"></select>





        var init = [
        {"year": "2017", "name": "Apples", "value": 20},
        {"year": "2017", "name": "Bananas","value": 12},
        {"year": "2017", "name": "Grapes", "value": 19},
        {"year": "2017", "name": "Lemons", "value": 5},
        {"year": "2017", "name": "Limes", "value": 16},
        {"year": "2017", "name": "Oranges", "value": 26},
        {"year": "2017", "name": "Pears","value": 30},
        {"year": "2018", "name": "Apples", "value": 10},
        {"year": "2018", "name": "Bananas","value": 42},
        {"year": "2018", "name": "Grapes", "value": 69},
        {"year": "2018", "name": "Lemons", "value": 15},
        {"year": "2018", "name": "Limes", "value": 26},
        {"year": "2018", "name": "Oranges", "value": 36},
        {"year": "2018", "name": "Pears","value": 20}
        ];

        chart(init)

        function chart(result) {

        var format = d3.format(",.0f")

        var years = [...new Set(result.map(d => d.year))]
        var fruit = [...new Set(result.map(d => d.name))]

        var options = d3.select("#year").selectAll("option")
        .data(years)
        .enter().append("option")
        .text(d => d)

        var svg = d3.select("#graphic"),
        margin = {top: 25, bottom: 10, left: 50, right: 45},
        width = +svg.attr("width") - margin.left - margin.right,
        height = +svg.attr("height") - margin.top - margin.bottom;

        var x = d3.scaleLinear()
        .range([margin.left, width - margin.right])

        var y = d3.scaleBand()
        .range([margin.top, height - margin.bottom])
        .padding(0.1)
        .paddingOuter(0.5)
        .paddingInner(0.5)

        var xAxis = svg.append("g")
        .attr("class", "x-axis")
        .attr("transform", `translate(0,${margin.top})`)

        var yAxis = svg.append("g")
        .attr("class", "y-axis")
        .attr("transform", `translate(${margin.left},0)`)

        update(d3.select("#year").property("value"), 750, 250)

        function update(input, speed, delay) {

        var data = result.filter(f => f.year == input)

        var sum = d3.sum(data, d => d.value)

        x.domain([0, d3.max(data, d => d.value)]).nice()

        svg.selectAll(".x-axis").transition().duration(speed)
        .call(d3.axisTop(x).tickSizeOuter(0));

        data.sort((a, b) => b.value - a.value)

        y.domain(data.map(d => d.name))

        svg.selectAll(".y-axis").transition().duration(speed)
        .call(d3.axisLeft(y));

        yAxis.selectAll("text").remove()
        yAxis.selectAll("line").remove()

        var bar = svg.selectAll(".bar")
        .data(data, d => d.name)

        bar.exit().remove();

        bar.enter().insert("g", ".y-axis").append("rect")
        .attr("class", "bar")
        .attr("fill", "#ccc")
        .attr("x", x(0))
        .attr("y", d => y(d.name))
        .attr("height", y.bandwidth())
        .merge(bar)
        .transition().duration(speed)
        .delay((_, i) => delay * i)
        .attr("y", d => y(d.name))
        .attr("width", d => x(d.value) - x(0));

        var value = svg.selectAll(".value")
        .data(data, d => d.name)

        value.exit().remove();

        value.enter().append("text")
        .attr("class", "value")
        .attr("opacity", 0)
        .attr("dy", 4)
        .attr("y", d => y(d.name) + y.bandwidth() / 2)
        .merge(value)
        .transition().duration(speed)
        .delay((_, i) => delay * i)
        .attr("opacity", 1)
        .attr("y", d => y(d.name) + y.bandwidth() / 2)
        .attr("x", d => x(d.value) + 5)
        .text(d => format((d.value / sum) * 100) + " %")

        var name = svg.selectAll(".name")
        .data(data, d => d.name)

        name.exit().remove();

        name.enter().append("text")
        .attr("class", "name")
        .attr("opacity", 0)
        .attr("dy", -5)
        .attr("y", d => y(d.name))
        .merge(name)
        .transition().duration(speed)
        .delay((_, i) => delay * i)
        .attr("opacity", 1)
        .attr("y", d => y(d.name))
        .attr("x", d => x(0) + 5)
        .text(d => d.name)
        }

        var select = d3.select("#year")
        .style("border-radius", "5px")
        .on("change", function() {
        update(this.value, 750, 0)
        })
        }

        body {
        margin: auto;
        width: 650px;
        font: 12px arial;
        }

        <script src="https://d3js.org/d3.v5.min.js"></script>
        <svg id="graphic" width="600" height="380"></svg><br>

        Choose year:
        <select id="year"></select>






        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered 9 hours ago









        Robert Andersson

        1,1991419




        1,1991419






























             

            draft saved


            draft discarded



















































             


            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53371846%2fd3-labelled-horizontal-chart-with-labels-and-animation%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Can a sorcerer learn a 5th-level spell early by creating spell slots using the Font of Magic feature?

            ts Property 'filter' does not exist on type '{}'

            mat-slide-toggle shouldn't change it's state when I click cancel in confirmation window