Skip to content

Instantly share code, notes, and snippets.

@syncopika
Last active August 27, 2016 23:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save syncopika/f1c9036b0deb058454f825238a95b6be to your computer and use it in GitHub Desktop.
Save syncopika/f1c9036b0deb058454f825238a95b6be to your computer and use it in GitHub Desktop.
updating a bar chart with d3.js (v4)
height: 800

view it here: http://bl.ocks.org/syncopika/f1c9036b0deb058454f825238a95b6be

Using some sample data from my YouTube analytics, you can see how to update a bar chart with different data sets. All the examples I've seen so far about updating a chart used .exit() and then .remove(), which didn't work for me. using .remove(), and then .exit(), seems to work. ^^ hope this is helpful.

<!DOCTYPE html>
<html>
<head>
<title>updating a bar chart with d3.js (v4)</title>
<script src="https://d3js.org/d3.v4.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
</head>
<style>
.radio{
text-align: center;
}
.row{
text-align: center;
}
</style>
<body>
<div class='container'>
<div class='row'>
<h2> watch time vs. age group</h2>
<p>total time watched: 1411 minutes</p>
<div class='radio'>
<label class='radio-inline'>
<input type="radio" name="gender" value="male" onclick='change(this.value)'> male
</label>
<label class='radio-inline'>
<input type="radio" name="gender" value="female" onclick='change(this.value)'> female
</label>
<label class='radio-inline'>
<input type="radio" name="gender" value="both" onclick='change(this.value)' checked > both
</label>
</div>
<svg class='chart'>
</svg>
</div>
</div>
</body>
<script>
//set up data
var bothData = [
{
"viewer_gender": "FEMALE",
"viewer_age": "AGE_13_17",
"channel_display_name": "syncopika",
"channel_id": "T2NUI3KLGK6sDILFbzUZZg",
"views": "3.3",
"watch_time_minutes": "2.8"
},
{
"viewer_gender": "MALE",
"viewer_age": "AGE_13_17",
"channel_display_name": "syncopika",
"channel_id": "T2NUI3KLGK6sDILFbzUZZg",
"views": "12.8",
"watch_time_minutes": "13.5"
},
{
"viewer_gender": "FEMALE",
"viewer_age": "AGE_18_24",
"channel_display_name": "syncopika",
"channel_id": "T2NUI3KLGK6sDILFbzUZZg",
"views": "7.1",
"watch_time_minutes": "6.6"
},
{
"viewer_gender": "MALE",
"viewer_age": "AGE_18_24",
"channel_display_name": "syncopika",
"channel_id": "T2NUI3KLGK6sDILFbzUZZg",
"views": "37.1",
"watch_time_minutes": "35.8"
},
{
"viewer_gender": "FEMALE",
"viewer_age": "AGE_25_34",
"channel_display_name": "syncopika",
"channel_id": "T2NUI3KLGK6sDILFbzUZZg",
"views": "2.7",
"watch_time_minutes": "3.9"
},
{
"viewer_gender": "MALE",
"viewer_age": "AGE_25_34",
"channel_display_name": "syncopika",
"channel_id": "T2NUI3KLGK6sDILFbzUZZg",
"views": "23.5",
"watch_time_minutes": "24.7"
},
{
"viewer_gender": "FEMALE",
"viewer_age": "AGE_35_44",
"channel_display_name": "syncopika",
"channel_id": "T2NUI3KLGK6sDILFbzUZZg",
"views": "1.0",
"watch_time_minutes": "0.8"
},
{
"viewer_gender": "MALE",
"viewer_age": "AGE_35_44",
"channel_display_name": "syncopika",
"channel_id": "T2NUI3KLGK6sDILFbzUZZg",
"views": "6.4",
"watch_time_minutes": "5.0"
},
{
"viewer_gender": "FEMALE",
"viewer_age": "AGE_45_54",
"channel_display_name": "syncopika",
"channel_id": "T2NUI3KLGK6sDILFbzUZZg",
"views": "0.7",
"watch_time_minutes": "1.3"
},
{
"viewer_gender": "MALE",
"viewer_age": "AGE_45_54",
"channel_display_name": "syncopika",
"channel_id": "T2NUI3KLGK6sDILFbzUZZg",
"views": "3.3",
"watch_time_minutes": "3.4"
},
{
"viewer_gender": "FEMALE",
"viewer_age": "AGE_55_64",
"channel_display_name": "syncopika",
"channel_id": "T2NUI3KLGK6sDILFbzUZZg",
"views": "0.1",
"watch_time_minutes": "0.1"
},
{
"viewer_gender": "MALE",
"viewer_age": "AGE_55_64",
"channel_display_name": "syncopika",
"channel_id": "T2NUI3KLGK6sDILFbzUZZg",
"views": "0.8",
"watch_time_minutes": "0.7"
},
{
"viewer_gender": "FEMALE",
"viewer_age": "AGE_65_",
"channel_display_name": "syncopika",
"channel_id": "T2NUI3KLGK6sDILFbzUZZg",
"views": "0.2",
"watch_time_minutes": "0.2"
},
{
"viewer_gender": "MALE",
"viewer_age": "AGE_65_",
"channel_display_name": "syncopika",
"channel_id": "T2NUI3KLGK6sDILFbzUZZg",
"views": "1.1",
"watch_time_minutes": "1.3"
}
];
var maleData = [];
var femaleData = [];
for(var i = 0; i < bothData.length; i++){
if(bothData[i]["viewer_gender"] === "MALE"){
maleData.push(bothData[i]);
}else{
femaleData.push(bothData[i]);
}
}
//functions for toggling between data
function change(value){
if(value === 'male'){
update(maleData);
}else if(value === 'female'){
update(femaleData);
}else{
update(bothData);
}
}
function update(data){
//set domain for the x axis
xChart.domain(data.map(function(d){ return d.viewer_age; }) );
//set domain for y axis
yChart.domain( [0, d3.max(data, function(d){ return +d.watch_time_minutes; })] );
//get the width of each bar
var barWidth = width / data.length;
//select all bars on the graph, take them out, and exit the previous data set.
//then you can add/enter the new data set
var bars = chart.selectAll(".bar")
.remove()
.exit()
.data(data)
//now actually give each rectangle the corresponding data
bars.enter()
.append("rect")
.attr("class", "bar")
.attr("x", function(d, i){ return i * barWidth + 1 })
.attr("y", function(d){ return yChart( d.watch_time_minutes); })
.attr("height", function(d){ return height - yChart(d.watch_time_minutes); })
.attr("width", barWidth - 1)
.attr("fill", function(d){
if(d.viewer_gender === "FEMALE"){
return "rgb(251,180,174)";
}else{
return "rgb(179,205,227)";
}
});
//left axis
chart.select('.y')
.call(yAxis)
//bottom axis
chart.select('.xAxis')
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.attr("transform", function(d){
return "rotate(-65)";
});
}//end update
//set up chart
var margin = {top: 20, right: 20, bottom: 95, left: 50};
var width = 800;
var height = 500;
var chart = d3.select(".chart")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var xChart = d3.scaleBand()
.range([0, width]);
var yChart = d3.scaleLinear()
.range([height, 0]);
var xAxis = d3.axisBottom(xChart);
var yAxis = d3.axisLeft(yChart);
//set up axes
//left axis
chart.append("g")
.attr("class", "y axis")
.call(yAxis)
//bottom axis
chart.append("g")
.attr("class", "xAxis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.attr("transform", function(d){
return "rotate(-65)";
});
//add labels
chart
.append("text")
.attr("transform", "translate(-35," + (height+margin.bottom)/2 + ") rotate(-90)")
.text("% of total watch time");
chart
.append("text")
.attr("transform", "translate(" + (width/2) + "," + (height + margin.bottom - 5) + ")")
.text("age group");
//use bothData to begin with
update(bothData);
</script>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment