|
<!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> |