D3.js中Population Pyramid详解
来源:互联网 发布:网络燃爆了什么意思 编辑:程序博客网 时间:2024/05/17 12:20
Population Pyramid
聊一聊人口金字塔图。
人口金字塔是按人口年龄和性别表示人口分布的特种塔状条形图,是形象地表示某一人口的年龄和性别构成的图形。——百度百科
一般的人口金字塔图如下图所示:
例如上图表示,2011年利比亚男女不同年龄阶段的比例分布情况。
而本篇要讲的Population Pyramid图,将男女人口数据画在了坐标轴的同一边,通过柱状图的覆盖来看不同年龄阶段的男女比例分布情况,如下图所示:
图中用粉色来标识女性的数据、蓝色标识男性的数据,数据重叠部分,由于粉色和蓝色重叠而呈现出紫色,例如70岁的人群当中,女性的比例比男性的多;而20岁的人群当中,男性的比例比女性的多。
接下来详细解释D3.js是如何实现这张人口金字塔图的。
index.html——源码
<!DOCTYPE html><meta charset="utf-8"><style>svg { font: 10px sans-serif;}.y.axis path { display: none;}.y.axis line { stroke: #fff; stroke-opacity: .2; shape-rendering: crispEdges;}.y.axis .zero line { stroke: #000; stroke-opacity: 1;}.title { font: 300 78px Helvetica Neue; fill: #666;}.birthyear,.age { text-anchor: middle;}.birthyear { fill: #fff;}rect { fill-opacity: .6; fill: #e377c2;}rect:first-child { fill: #1f77b4;}</style><body><script src="//d3js.org/d3.v3.min.js"></script><script>// 定义相关尺寸// margin定义svg画图的上 、右、下、左的外边距var margin = {top: 20, right: 40, bottom: 30, left: 20}, // 计算宽度 width = 960 - margin.left - margin.right, // 计算高度 height = 500 - margin.top - margin.bottom, // 计算柱状条的宽度,其中19由于分了19个年龄段 barWidth = Math.floor(width / 19) - 1;// 为x轴定义线性比例尺,值域range的定义可以看出,x轴的刻度尺都会位于柱状图的底部中间位置var x = d3.scale.linear() .range([barWidth / 2, width - barWidth / 2]);// 为y轴定义线性比例尺,值域为height到0var y = d3.scale.linear() .range([height, 0]);// 定义y坐标轴var yAxis = d3.svg.axis() // 设置y轴的比例尺 .scale(y) // y轴坐标刻度文字在右侧 .orient("right") // 这里设置为“-width”,个人理解为,y轴刻度线本应该在轴的右边,设置为负数,刻度线绘制在y轴的左边 // 而且刻度线的长度为图形的宽度,表现在图上就是那些横穿柱状条的白色线,看不见白色线的部分是因为 // 图背景和刻度线都是白色 .tickSize(-width) // 设置y轴刻度的格式 .tickFormat(function(d) { return Math.round(d / 1e6) + "M"; });// An SVG element with a bottom-right origin.// 定义svg画布var svg = d3.select("body").append("svg") // 设置svg画布的宽度 .attr("width", width + margin.left + margin.right) // 设置svg画布的高度 .attr("height", height + margin.top + margin.bottom) .append("g") // 定位svg画布 .attr("transform", "translate(" + margin.left + "," + margin.top + ")");// A sliding container to hold the bars by birthyear.// 定义表示 出生年 的元素var birthyears = svg.append("g") .attr("class", "birthyears");// A label for the current year.// 绘制当年的年份文字,即图中左上角的 2000字样var title = svg.append("text") .attr("class", "title") .attr("dy", ".71em") .text(2000);// 处理数据d3.csv("population.csv", function(error, data) { // Convert strings to numbers. // 将csv数据文件中的pepole,yaer,age字段的值转换成数字类型 data.forEach(function(d) { d.people = +d.people; d.year = +d.year; d.age = +d.age; }); // Compute the extent of the data set in age and years. // 计算年龄和年份数据集的范围 // 获取最大年龄 var age1 = d3.max(data, function(d) { return d.age; }), // 获取最小年份 year0 = d3.min(data, function(d) { return d.year; }), // 获取最大年份 year1 = d3.max(data, function(d) { return d.year; }), // 设置year为最大年份 year = year1; // Update the scale domains. // 上面在定义x,y的比例尺时没有设置“定义域”,此处开始设置 // 设置x比例尺的定义域,可以看出,x轴表示年龄的变化 x.domain([year1 - age1, year1]); // 设置y比例尺的定义域,可以看出,y轴表示人口数量的变化 y.domain([0, d3.max(data, function(d) { return d.people; })]); // Produce a map from year and birthyear to [male, female]. // d3.nest()函数用来将数据分组为任意层次结构 // d3.nest().key(fun)用来对每数据以fun函数返回的键值来进行分组,此处以year来进行分组 // 后,返回的是以year作为键的不同的数组;再以year-age作为键值进行第二次分组; // rollup()函数将用返回的值d.people来替换key所对应的值 // d3.nest().map()返回最终的分组后的层次结构的数据 // 可以通过在浏览器中调试状态下看到最终返回的data数组是以年份进行第一层分组,每个年份下又以 // d.year -d.age进行了第二层的分组,第二层分组对应的数据为rollup中指定的d.people。 data = d3.nest() .key(function(d) { return d.year; }) .key(function(d) { return d.year - d.age; }) .rollup(function(v) { return v.map(function(d) { return d.people; }); }) .map(data); // Add an axis to show the population values. // 绘制y轴 svg.append("g") .attr("class", "y axis") // 将y轴定位到画布右侧 .attr("transform", "translate(" + width + ",0)") // 对该g元素执行yAxis定义的操作 .call(yAxis) .selectAll("g") // 筛选出 value为空的 .filter(function(value) { return !value; }) // 将筛选出的value为空的元素,为期添加zero样式类 .classed("zero", true); // Add labeled rects for each birthyear (so that no enter or exit is required). // 为表示出生年份的元素绑定数据,定义年份步长为5年 var birthyear = birthyears.selectAll(".birthyear") .data(d3.range(year0 - age1, year1 + 1, 5)) .enter().append("g") .attr("class", "birthyear") // 定位年份的位置,通过上面定义的x()比例尺函数来计算 .attr("transform", function(birthyear) { return "translate(" + x(birthyear) + ",0)"; }); // 绘制柱状条 birthyear.selectAll("rect") // 获取2000这一年里,出生年份为birthyear的分组 .data(function(birthyear) { return data[year][birthyear] || [0, 0]; }) .enter().append("rect") .attr("x", -barWidth / 2) .attr("width", barWidth) // 设置y位置通过y比例尺来计算 .attr("y", y) // 设置柱状条的高度 .attr("height", function(value) { return height - y(value); }); // Add labels to show birthyear. // 添加出生年份文字 birthyear.append("text") .attr("y", height - 4) .text(function(birthyear) { return birthyear; }); // Add labels to show age (separate; not animated). // 添加年龄文字 svg.selectAll(".age") // 为年龄文字绑定数据,年龄步长为5 .data(d3.range(0, age1 + 1, 5)) .enter().append("text") .attr("class", "age") .attr("x", function(age) { return x(year - age); }) .attr("y", height + 4) .attr("dy", ".71em") .text(function(age) { return age; }); // Allow the arrow keys to change the displayed year. // 通过方向键“←”和“→”来查滑动年份窗口,查看更多年份的人口分布情况 // 用focus()方法可把键盘焦点给予当前窗口 window.focus(); //为方向键“←”和“→”操作绑定动作 d3.select(window).on("keydown", function() { switch (d3.event.keyCode) { // 若为向左←,则将当前年份倒退10年 case 37: year = Math.max(year0, year - 10); break; // 若为向右→,则将当前年份向前推进10年 case 39: year = Math.min(year1, year + 10); break; } // 对图进行更新 update(); }); // 定义更改年份窗口后,对图进行更新的操作 function update() { // 若更改年份窗口后,data中无当前年份的数据,则不进行任何操作,直接返回 if (!(year in data)) return; // 托更改年份窗口后,data中有当前年份数据,则首先更新左上角显示的年份 title.text(year); // 更新出生年份,此处定义更新过渡动画 birthyears.transition() // 动作持续750毫秒 .duration(750) // 定义更新动作 .attr("transform", "translate(" + (x(year1) - x(year)) + ",0)"); // 更新柱状条 birthyear.selectAll("rect") // 绑定新的年份窗口数据 .data(function(birthyear) { return data[year][birthyear] || [0, 0]; }) // 定义过渡动画 .transition() .duration(750) .attr("y", y) .attr("height", function(value) { return height - y(value); }); }});</script>
至此,人口金字塔图的实现解释完毕。实现此人口金字塔图的重点:
一是通过d3.nest()数据处理方法,对官网给出的population.csv中的数据进行分组处理。
二是x,y坐标轴的刻度的计算方法。
今天尽管阳光明媚,但是空气冷凉,适合坐在室内窗边安安静静地就很美好。
阅读全文
0 0
- D3.js中Population Pyramid详解
- D3.js 中 Box Plots详解
- D3.js 中Bubble Chart详解
- D3.js中Bullet Charts详解
- D3.js中Radial Cluster Dendrogram详解
- D3.js中Force-Directed Graph详解
- D3.js中Circle Packing详解
- D3.js中Stream graph详解
- d3.js d3.scale.ordinal() --详解 rangeBands
- D3.js中Stacked-to-Grouped Bars详解
- D3.js中使用scale
- D3学习之:D3.js中的12中地图投影方式
- D3.JS: 在SVG中使用d3创建HTML标签
- D3.js 动态数据刷新视图详解
- D3.js中的Calendar View详解
- D3.js 中的 Non-Contiguous Cartogram详解
- D3.js中的Chord Diagram详解
- D3.js中的Cluster Dendrogram详解
- 洛谷1879 [USACO06NOV]玉米田Corn Fields
- ssh远程后台执行matlab程序(可并行优化)
- 【LeetCode】39.Combination Sum(Medium)解题报告
- 2017.12.11 Date格式化
- epoll剖析
- D3.js中Population Pyramid详解
- 设计模式(十)------23种设计模式(3):抽象工厂模式
- MIME,拓展名需要相应的软件打开
- IIS无法打开WebService的wsdl,总是跳到登录页面
- 【HNOI2017】大佬-dalao
- Python使用系统聚类方法进行数据分类案例一则
- Go简单的网站开发
- 二维码工具类,图片加水印工具类
- Shape of my heart