(本文在较早之前在本人知乎账号为“BOOM”的数据可视化专栏发表过:知乎链接,所以也可到本人知乎上的文章分享查看更多文章)
(本文章代码来自网络与《D3API详解》这本书,收集做学习交流之用)
说明:本文实用d3.js版本为v3。
1、捆绑布局
1.1、简介:
捆绑布局根据结点数据输入确定结点的父子关系,再根据边数据输入确定结点之间的边怎么画,当从一个结点映射出去的连接比较多时看上去像是形成一捆绳,所以叫捆图。适合展示如demo所示各大城市之间高铁连接关系这样的情况。
1.2、demo:
多个城市之间的高铁连接情况:
图11.3、代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>捆图</title>
<style>
body{
background-color: #000000;
}
.node circle {
stroke: black;
stroke-width: 2px;
}
.node text{
font-size: 12px;
font-family: simsun;
}
.link {
fill: none;
stroke: white;
stroke-opacity: .5;
stroke-width: 8px;
}
</style>
</head>
<body>
<script src="../../d3.js"></script>
<script>
var width = 1370; //SVG绘制区域的宽度
var height = 670; //SVG绘制区域的高度
var svg = d3.select("body") //选择<body>
.append("svg") //在<body>中添加<svg>
.attr("width", width) //设定<svg>的宽度属性
.attr("height", height);//设定<svg>的高度属性
//1\. 确定初始数据
var vertex = {
name: "",
children:[
{name: "北京"},{name: "上海"},{name: "杭州"},
{name: "广州"},{name: "桂林"},{name: "昆明"},
{name: "成都"},{name: "西安"},{name: "太原"}
]
};
var edges = [
{source: "北京", target: "上海"},
{source: "北京", target: "广州"},
{source: "北京", target: "杭州"},
{source: "北京", target: "西安"},
{source: "北京", target: "成都"},
{source: "北京", target: "太原"},
{source: "北京", target: "桂林"},
{source: "北京", target: "昆明"},
{source: "北京", target: "成都"},
{source: "上海", target: "杭州"},
{source: "昆明", target: "成都"},
{source: "西安", target: "太原"}
];
var Zoom_data = 400;//这个值可以调节图的大小
//2\. 转换数据
var cluster = d3.layout.cluster()
.size([360, width/2 - Zoom_data])
.separation(function(a, b) { return (a.parent == b.parent ? 1 : 2) / a.depth; });
var bundle = d3.layout.bundle();
//数据接口
var nodes = cluster.nodes(vertex);
var oLinks = map(nodes, edges);
var links = bundle(oLinks);
//将links中的source和target由名称替换成节点
function map( nodes, links ){
var hash = [];
for(var i = 0; i < nodes.length; i++){
hash[nodes[i].name] = nodes[i];
}
var resultLinks = [];
for(var j = 0; j < links.length; j++){
resultLinks.push({ source: hash[ links[j].source ],
target: hash[ links[j].target ]
});
}
return resultLinks;
}
//3\. 绘图
var line = d3.svg.line.radial()
.interpolate("bundle")
.tension(.85)
.radius(function(d) { return d.y; })
.angle(function(d) { return d.x / 180 * Math.PI; });
gBundle = svg.append("g")
.attr("transform", "translate(" + (width/2) + "," + (height/2) + ")");
var color = d3.scale.category20c();
var link = gBundle.selectAll(".link")
.data(links)
.enter()
.append("path")
.attr("class", "link")
.attr("d", line); //使用线段生成器
var node = gBundle.selectAll(".node")
.data( nodes.filter(function(d) { return !d.children; }) )
.enter()
.append("g")
.attr("class", "node")
.attr("transform", function(d) {
return "rotate(" + (d.x- 90) + ")translate(" + d.y + ")" + "rotate("+ (90 - d.x) +")";
});
node.append("circle")
.attr("r", 20)
.style("fill",function(d,i){ return color(i); });
node.append("text")
.attr("dy",".2em")
.style("text-anchor", "middle")
.text(function(d) { return d.name; });
</script>
</body>
</html>
图2
2、弦布局
2.1、简介:
弦图用来展示一组实体之间的关系,通过在不同的弧线之间画出二次贝塞尔曲线,将实体之间的关系表示在一张弦图中。下面展示了一个弦图,表示五个城市人口互相之间的来源关系,比如北京有2015人来自上海,上海有2060人来自广州。
2.2、demo:
图32.3、代码:
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>弦图</title>
<style>
body{
background-color: #000000;
}
</style>
</head>
<body>
<script src="../../d3.js"></script>
<script>
var city_name = ["北京","上海","广州","深圳","香港"];
var population = [
[1000,3015,4567,1234,3714],
[3214,2000,2060,124,3234],
[8761,6545,3000,8045,647],
[3211,1067,3214,4000,1006],
[2146,1034,6745,4764,5000]
];
var chord_layout = d3.layout.chord()
.padding (0.03)//取得或设置弦片段间的角填充,也就是每一个弦片段的间距啦
.sortSubgroups(d3.descending)
.matrix(population); // 取得或设置布局需要的关联矩阵数据
var width = 800,
height = 670;
var innerRadius = width/2*0.7,
outerRadius = innerRadius*1.1;
var color = d3.scale.category20();
var svg = d3.select("body").append("svg")
.attr("width",width)
.attr("height",height)
.append("g")
.attr("transform","translate("+width/2+","+height/2+")");
var outer_arc = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
var g_outer = svg.append("g");
g_outer.selectAll("path")
.data(chord_layout.groups) //返回index(行索引)、subindex(列索引)、startAngle、endAngle、value
.enter()
.append("path")
.style("fill", function (d) {
return color(d.index)
}
)
.style("stroke", function (d) {
return color(d.index)
})
.attr("d",outer_arc);
g_outer.selectAll("text")
.data(chord_layout.groups)
.enter()
.append("text")
.each(function(d,i){
d.angle = (d.startAngle+ d.endAngle)/2;
d.name = city_name[i];
}) //表示对于任何一个绑定的元素,都执行后面的无名函数 function 的代码,这里的代码为: 计算一个角度,赋值给 d.angle ;获取城市的名称。
.attr("dy",".35em")
.attr("transform",function(d){
return "rotate("+(d.angle*180/Math.PI)+")"+"translate(0,"+-1.0*(outerRadius+10)+")"+((d.angle>Math.PI*3/4 && d.angle<Math.PI*5/4)?"rotate(180)":"");
})//在用 transform 进行位移时,要注意转换的顺序: rotate -> translate,最后一行转换代码表示:当角度在135°到225°之间时,旋转180°。否则下方的文字是倒的,不利于观看。
.text(function(d){return d.name;})
.style("stroke","white");
var inner_chord = d3.svg.chord()
.radius(innerRadius);
svg.append("g")
.attr("class","chord")
.selectAll("path")
.data(chord_layout.chords) //返回index(行索引)、subindex(列索引)、startAngle、endAngle、value等参数
.enter()
.append("path")
.attr("d",inner_chord)
.style("fill", function(d) { return color(d.source.index); })
.style("opacity",0.5)
.on("mouseover",function(d,i){
d3.select(this)
.style("fill","white");
})
.on("mouseout",function(d,i){
d3.select(this)
.transition()
.duration(1000)
.style("fill",color(d.source.index))
})
</script>
</body>
</html>
图4
3、树布局
3.1、简介:
树布局能够用莱茵戈尔德-蒂尔福德算法产生一个整洁的树状节点-连接图,下面使用了一个国家名,省份名与市名的从属关系树状图展示效果。
3.2、demo:
图53.3、代码:
<html>
<head>
<meta charset="utf-8">
<title>树状图</title>
<style>
body{
background-color: #000000;
}
.node circle {
fill: #fff;
stroke: steelblue;
stroke-width: 2px;
}
.node {
font: 16px sans-serif;
}
.link {
fill: none;
stroke: white;
stroke-width: 3.5px;
opacity: 0.5;
}
</style>
</head>
<body>
<script src="../../d3.js"></script>
<script>
var width = 680,
height = 670;
var tree = d3.layout.tree()
.size([width, height-200])
.separation(function(a, b) { return (a.parent == b.parent ? 1 : 2); });
var diagonal = d3.svg.diagonal()
.projection(function(d) { return [d.y, d.x]; });
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(40,0)");
d3.json("city_tree.json", function(error, root) {
var nodes = tree.nodes(root);
var links = tree.links(nodes);
var link = svg.selectAll(".link")
.data(links)
.enter()
.append("path")
.attr("class", "link")
.attr("d", diagonal);
var node = svg.selectAll(".node")
.data(nodes)
.enter()
.append("g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; });
node.append("circle")
.attr("r", 4.5);
node.append("text")
.attr("dx", function(d) { return d.children ? -8 : 8; })
.attr("dy", 3)
.style("text-anchor", function(d) { return d.children ? "end" : "start"; })
.style("stroke","yellow")
.text(function(d) { return d.name; });
});
</script>
</body>
</html>
/*数据文件city_tree.json*/
{
"name":"中国",
"children":
[
{
"name":"浙江" ,
"children":
[
{"name":"杭州" },
{"name":"宁波" },
{"name":"温州" },
{"name":"绍兴" }
]
},
{
"name":"广西" ,
"children":
[
{
"name":"桂林",
"children":
[
{"name":"秀峰区"},
{"name":"叠彩区"},
{"name":"象山区"},
{"name":"七星区"}
]
},
{"name":"南宁"},
{"name":"柳州"},
{"name":"防城港"}
]
},
{
"name":"黑龙江",
"children":
[
{"name":"哈尔滨"},
{"name":"齐齐哈尔"},
{"name":"牡丹江"},
{"name":"大庆"}
]
},
{
"name":"新疆" ,
"children":
[
{"name":"乌鲁木齐"},
{"name":"克拉玛依"},
{"name":"吐鲁番"},
{"name":"哈密"}
]
}
]
}
图6
4、力布局
4.1、简介:
力布局使用位置Verlet整合算法实现,适合网络型、社交型图数据的可视化展示。
4.2、demo:
图74.3、代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
.link {
stroke: #e2e0e1;
opacity: 0.5;
}
.node text {
pointer-events: auto;
font: 10px sans-serif;
color:white;
opacity: 0.0;
}
#Table{
color:white;
}
p,b{
color:white;
}
</style>
</head>
<body bgcolor="black">
<script src="d3.v3.min.js"></script>
<script>
var width = 1450,height = 800;
var radius = 15;
var colors = d3.scale.category20();
var rscale = d3.scale.linear()
.domain([1,30])
.range([3,15]);
var color = d3.scale.category20();
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
/*.call(
d3.behavior.zoom()
.scaleExtent([1,20])
.on("zoom",zoom)
)*/
.append("g");
//zoom是定义缩放事件的
function zoom(){
svg.attr("transform","translate("+d3.event.translate+")scale("+d3.event.scale+")");
}
var force = d3.layout.force()
.gravity(0.05)
.distance(90)
.charge(-80)
.size([width, height]);
var label_text_1 = svg.append("text")
.attr("class","labeltext")
.attr("x",10)
.attr("y",16)
.text("");
var label_text_2 = svg.append("text")
.attr("class","labeltext")
.attr("x",10)
.attr("y",40)
.text("");
d3.json("../haitun - 1000.json", function(error, json) {
if (error){throw error;}
force
.nodes(json.nodes)
.links(json.links)
.on("tick", tick)
.start();
link = svg.selectAll(".link")
.data(json.links)
.enter().append("line")
.attr("class", "link")
.attr("id",function(d){
return d.value1;
})
//.attr("stroke-width","2.5px")
.attr("stroke","#e2dab8")
.attr("stroke-width","1.5px");
/****下面node不加var是为了把node声明为全局变量,让所在函数作用域外的其他函数也能使用该变量**/
node=svg.selectAll(".node")
.data(json.nodes)
.enter().append("g")
.attr("class", "node")
.call(force.drag);
node.append("circle")
.attr("r",function(d){
return rscale(d.number);
})
/*.attr("r",8)*/
.attr("Id",function(d){
return d.id;
})
.attr("class",function(d){
return d.value1
})
.attr("stroke","blue")
.attr("stroke-width",function(d){
return 1;
})
.style("fill",function(d,i){
return color(i);
});
var drag = force.drag()
.on("dragstart", function (d, i) {
d.fixed = true; //拖拽开始后设定被拖拽对象为固定
label_text_2.text("");
})
.on("dragend", function (d, i) {
label_text_2.text("");
})
.on("drag", function (d, i) {
label_text_2.text("");
});
node.append("text")
.attr("dx", -5)//dx值可以调节text文本相对与圆点circle的位置
.attr("dy", ".35em")
.attr("class",function(d){
return d.value1
})
.attr("Id",function(d){
return d.id;
})
.attr("val",function(d){
return d.value1;
})
.text(function (d) {
return d.id
})
.style("fill","white")
.on("dblclick", function (d, i) {
d.fixed = false;
})
.on("mouseover", function (d, i) {
d3.select(this)
.style("opacity","0.0");})
.on("mouseout", function (d, i) {
d3.select(this)
.style("opacity","0.0");})
.call(drag);
/*force.on("tick", function () {*/
function tick(){
link.attr("x1", function (d) {
return d.source.x;
})
.attr("y1", function (d) {
return d.source.y;
})
.attr("x2", function (d) {
return d.target.x;
})
.attr("y2", function (d) {
return d.target.y;
});
node.attr("transform", function (d) {
return "translate(" + d.x + "," + d.y + ")";
});
}
});
图8
数据文件过大,所以我只列出结点数据和边数据格式截图:
结点:
图9边:
图105、包布局
5.1、简介:
包图采用包含(嵌套)来表现层级结构,能清晰地展现分层效果,但是有浪费空间的缺点。
5.2、demo:
图115.3、代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body{ background-color: #000000; }
circle { stroke: #000; }
text{ stroke:black; font-size: 15px; }
</style>
</head>
<body>
<script src="../../d3.js"></script>
<script>
var root = { children: [ { children: [ {value: 1}, {value: 1}, {value: 1}, {value: 1}, {value: 1} ] }, { children: [ {value: 1}, {value: 3}, {value: 2} ] } ] };
var width = 960, height = 500;
var color =d3.scale.category20();
var svg = d3.select("body").append("svg") .attr("width", width) .attr("height", height);
var pack = d3.layout.pack() .size([width, height]);
node = svg.selectAll("circle") .data(pack.nodes(root))
.enter()
.append("circle")
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
.attr("r", function(d) { return d.r; })
.attr("fill", function(d,i) { return color(i); });
node.append("text")
.attr("dx", function(d) { return d.children ? -8 : 8; })
.attr("dy", 3)
.style("text-anchor", function(d) { return d.children ? "end" : "start"; }) .text(function(d) { return d.value; });
</script>
</body>
</html>
6、分区布局
6.1、简介:
分区布局将会产生邻接的图形:一个节点-连接的树状填充体。结点将被绘制成实心面积图(弧或者矩形),每个节点相对于其他节点的位置显示出了层级结构。
6.2、demo:
6.2.1、城市数据的旭日分区图:
图126.2.2、冰柱图:
图136.3、代码:
6.3.1、旭日图代码:
<html>
<head>
<meta charset="utf-8">
<title>Circle - Partition</title>
</head>
<style> body{ background-color: #000000; } </style>
<body>
<script src="../../d3.js"></script>
<script>
var width = 1200, height = 670, radius = Math.min(width, height) / 2 , color = d3.scale.category20();
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + radius*2 + "," + radius + ")");
var partition = d3.layout.partition() .sort(null) .size([2 * Math.PI, radius * radius]) .value(function(d) { return 1; });
var arc = d3.svg.arc() .startAngle(function(d) { return d.x; }) .endAngle(function(d) { return d.x + d.dx; }) .innerRadius(function(d) { return Math.sqrt(d.y); }) .outerRadius(function(d) { return Math.sqrt(d.y + d.dy); }); d3.json("city_tree.json", function(error, root) {
if(error) console.log(error);
console.log(root);
var nodes = partition.nodes(root);
var links = partition.links(nodes);
console.log(nodes);
var arcs = svg.selectAll("g") .data(nodes) .enter().append("g"); arcs.append("path")
.attr("display", function(d) { return d.depth ? null : "none"; }) // hide inner ring .attr("d", arc) .style("stroke", "#fff") .style("fill", function(d) {
return color((d.children ? d : d.parent).name); }) .
on("mouseover",function(d){ d3.select(this) .style("fill","yellow"); }) .on("mouseout",function(d){ d3.select(this) .transition() .duration(200) .style("fill", function(d) {
return color((d.children ? d : d.parent).name); }); });
arcs.append("text") .style("font-size", "18px") .style("font-family", "simsun") .style("stroke","blue") .attr("text-anchor","middle") .attr("transform",function(d,i){ //第一个元素(最中间的),只平移不旋转 if( i == 0 ) return "translate(" + arc.centroid(d) + ")";
//其他的元素,既平移也旋转
var r = 0;
if( (d.x+d.dx/2)/Math.PI*180 < 180 )
// 0 - 180 度以内的 r = 180 * ((d.x + d.dx / 2 - Math.PI / 2) / Math.PI);
else
// 180 - 360 度以内的 r = 180 * ((d.x + d.dx / 2 + Math.PI / 2) / Math.PI);
//既平移也旋转
return "translate(" + arc.centroid(d) + ")" + "rotate(" + r + ")"; }) .text(function(d) { return d.name; }); });
</script>
</body>
</html>
数据文件同树布局中的city_tree.json。
6.3.2、冰柱图代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>testD3-34-icicle.html</title>
<style>
body{
background-color: #000000;
}
.node {
fill: #ddd;
stroke: #fff;
}
.label {
font: 15px sans-serif;
text-anchor: middle;
}
</style>
</head>
<body>
<script src="../../d3.js" charset="utf-8" ></script>
<script>
var width = 960,
height = 500;
var color = d3.scale.category20();
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
// (1)冰柱布局
var partition = d3.layout.partition()//递归分割节点树到一个旭日或冰柱。
.size([width, height])//在x和y指定的布局大小。
.value(function(d) { return d.size; });
d3.json("Ice.json", function(error, root) {//数据接口
// (2) 用冰柱图布局转换数据
var nodes = partition.nodes(root);//计算分区布局并返回节点的数组。
// (3) 设置文字和节点
svg.selectAll(".node")
.data(nodes)
.enter().append("rect")
.attr("class", "node")
.attr("x", function(d) { return d.x; })
.attr("y", function(d) { return d.y; })
.attr("width", function(d) { return d.dx; })
.attr("height", function(d) { return d.dy; })
.style("fill", function(d) { //颜色:有孩子则返回自己的颜色,无孩子则返回爸爸的颜色
return color((d.children ? d : d.parent).name);
});
svg.selectAll(".label")
.data(nodes.filter(function(d) {
return d.dx > 6;
}))
.enter().append("text")
.attr("class", "label")
.attr("dy", ".35em")
.attr("transform", function(d) {
return "translate(" + (d.x + d.dx / 2) + "," + (d.y + d.dy / 2) + ")rotate(90)";
})
.text(function(d) { return d.name; });
});
</script>
</body>
</html>
图14
数据文件(Ice.json):
{
"name": "AAA",
"children": [
{
"name": "BBB",
"children": [
{
"name": "CCC",
"children": [
{
"name": "DDD",
"children": [
{ "name": "EEE", "size": 73 },
{ "name": "EEE", "size": 73 },
{ "name": "EEE", "size": 73 },
{ "name": "EEE", "size": 73 },
{ "name": "EEE", "size": 73 },
{ "name": "EEE", "size": 73 },
{ "name": "EEE", "size": 73 },
{ "name": "EEE", "size": 73 },
{ "name": "EEE", "size": 73 },
{ "name": "EEE", "size": 73 },
{ "name": "EEE", "size": 73 },
{ "name": "EEE", "size": 73 },
{ "name": "EEE", "size": 73 },
{ "name": "EEE", "size": 73 },
{ "name": "EEE", "size": 73 },
{ "name": "EEE", "size": 73 }
]
},
{ "name": "DDD", "size": 73 },
{ "name": "DDD", "size": 39 },
{ "name": "DDD", "size": 67 },
{ "name": "DDD", "size": 73 },
{ "name": "DDD", "size": 39 },
{ "name": "DDD", "size": 67 },
{ "name": "DDD", "size": 73 },
{ "name": "DDD", "size": 39 },
{ "name": "DDD", "size": 67 },
{ "name": "DDD", "size": 73 },
{ "name": "DDD", "size": 39 },
{ "name": "DDD", "size": 67 },
{ "name": "DDD", "size": 73 },
{ "name": "DDD", "size": 39 },
{ "name": "DDD", "size": 67 },
{ "name": "DDD", "size": 73 }
]
},
{ "name": "CCC", "size": 67 },
{ "name": "CCC", "size": 73 },
{ "name": "CCC", "size": 39 },
{ "name": "CCC", "size": 67 },
{ "name": "CCC", "size": 73 },
{ "name": "CCC", "size": 39 },
{ "name": "CCC", "size": 67 },
{ "name": "CCC", "size": 73 },
{ "name": "CCC", "size": 39 },
{ "name": "CCC", "size": 67 },
{ "name": "CCC", "size": 73 },
{ "name": "CCC", "size": 39 },
{ "name": "CCC", "size": 67 },
{ "name": "CCC", "size": 73 },
{ "name": "CCC", "size": 39 },
{ "name": "CCC", "size": 67 },
{ "name": "CCC", "size": 73 }
]
},
{ "name": "BBB", "size": 39 },
{ "name": "BBB", "size": 67 },
{ "name": "BBB", "size": 73 }
]
}
图15
7、堆叠布局
7.1、简介:
堆叠布局需要一个二维的数据数组,并计算基准线。堆叠图可以被水平、垂直叠放,或者径向叠放。
7.2、demo:
面积堆叠图:
图16方块堆叠图:
图177.3、代码(面积堆叠图):
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style> body{ background-color: #000000; } </style>
</head>
<body>
<script src="../../d3.js"></script>
<script>
var width = 1300, height = 670;
var dataset = [ [ { x: 0, y: 5 },{ x: 1, y: 4 },{ x: 2, y: 2 },{ x: 3, y: 2 }, { x: 4, y: 3 },{ x: 5, y: 1 },{ x: 6, y: 2 },{ x: 7, y: 2 } ],[ { x: 0, y: 2 },{ x: 1, y: 5 },{ x: 2, y: 3 },{ x: 3, y: 3 }, { x: 4, y: 1 },{ x: 5, y: 5 },{ x: 6, y: 3 },{ x: 7, y: 2 } ],[ { x: 0, y: 5 },{ x: 1, y: 8 },{ x: 2, y: 1 },{ x: 3, y: 4 }, { x: 4, y: 3 },{ x: 5, y: 7 },{ x: 6, y: 2 },{ x: 7, y: 6 } ] ];
var stack = d3.layout.stack() (dataset);
var xScale = d3.scale.ordinal() .domain(d3.range(dataset[0].length)) .rangeRoundBands([0, width/2], 0.01);
var maxHeight=d3.max(dataset, function(d) { return d3.max(d, function(d) { return d.y0 + d.y; }); });
var yScale = d3.scale.linear() .domain([0, maxHeight]) .range([0, height]);
var colors = d3.scale.category20();
var svg = d3.select("body") .append("svg") .attr("width", width) .attr("height", height);
var groups = svg.selectAll("g") .data(dataset) .enter() .append("g") .style("fill", function(d, i) { return colors(i); });
var area = d3.svg.area() .interpolate("cardinal") .x(function(d,i) { return xScale(i); }) .y0(function(d) { return height-yScale(d.y0 + d.y); }) .y1(function(d) { return height-yScale(d.y0); });
groups.append("path") .attr("d", function(d) { return area(d); }) .style("fill", function(d, i) { return colors(i); });
</script>
</body>
</html>
8、直方图布局
8.1、简介:
直方图布局可以用来表示数据分布,通过将离散数据点分组归纳到矩形条例绘制。
8.2、demo:
图188.3、代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body{
background-color: #000000;
}
.bar text{
font-weight:bold;
font-size:16px;
}
.bar rect {
fill: blue;
shape-rendering: crispEdges;
}
.axis path, .axis line {
fill: none;
stroke: white;
shape-rendering: crispEdges;
}
</style>
</head>
<body>
<script src="../../d3.js"></script>
<script>
var values = [0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,0.2,0.3,0.4,
0.5,0.5,0.5,0.5,0.5,0.1,0.1,0.7,0.7,0.7,0.6,0.4,0.8];
var width = 960,
height = 500,
padding=6;
var x = d3.scale.linear()
.domain([0, 1])
.range([0, width/2]);
var format = d3.format(".2f");
var data = d3.layout.histogram()
.bins(x.ticks(10))
// .frequency(false) //频率
.frequency(true) //频数,默认情况
(values);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var y = d3.scale.linear()
.domain([0, 0.01+d3.max(data, function(d) { return d.y; })])
.range([height, 0]);
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var svg = d3.select("body").append("svg")
.attr("width", width+30)
.attr("height", height+30)
.attr("stroke","yellow")
.append("g")
.attr("transform", "translate(" + padding*10 + "," + padding + ")");
var bar = svg.selectAll(".bar")
.data(data)
.enter().append("g")
.attr("class", "bar")
.attr("transform", function(d) { return "translate(" + x(d.x) + "," + y(d.y) + ")"; });
bar.append("rect")
.attr("x",padding)
.attr("width", x(data[0].dx)-1)
.attr("height", function(d) { return height - y(d.y); });
bar.append("text")
.attr("dy", ".75em")
.attr("y", 6)
.attr("x", x(data[0].dx) / 2)
.attr("text-anchor", "middle")
.text(function(d) { return format(d.y); })
.attr("fill", "yellow");
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate("+padding+"," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate("+padding+"," + 0 + ")")
.call(yAxis);
</script>
</body>
</html>
图19
9、饼布局
9.1、简介:
展示离散数据点百分占比或者大小比较,很常见。
9.2、demo:
图209.3、代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>testD3-20-pie.html</title>
<script type="text/javascript" src="../../d3.js"></script>
<style type="text/css">
body{
background-color: #000000;
}
</style>
</head>
<body>
<script type="text/javascript">
var dataset=[5,10,20,40,6,25];
//(1)转化数据为适合生成饼图的对象数组
var pie=d3.layout.pie(dataset);
var h=750;
var w=650;
var outerRadius=w/2;//外半径
//(7)圆环内半径
var innerRadius=w/1024;//增大这个值可以让饼图变成圆环图
//(2)用svg的path绘制弧形的内置方法
var arc=d3.svg.arc()//设置弧度的内外径,等待传入的数据生成弧度
.outerRadius(outerRadius)
.innerRadius(innerRadius);
var svg=d3.select("body")
.append("svg")
.attr("width",w)
.attr("height",h);
//(3)颜色函数
var color=d3.scale.category10();//创建序数比例尺和包括10中颜色的输出范围
//(4)准备分组,把每个分组移到图表中心
var arcs=svg.selectAll("g.arc")
.data(pie(dataset))
.enter()
.append("g")
.attr("class","arc")
//移到图表中心
.attr("transform","translate("+outerRadius+","+outerRadius+")");//translate(a,b)a表示横坐标起点,b表示纵坐标起点
//(5)为组中每个元素绘制弧形路路径
arcs.append("path")//每个g元素都追加一个path元素用绑定到这个g的数据d生成路径信息
.attr("fill",function(d,i){//填充颜色
return color(i);
})
.attr("d",arc);//将角度转为弧度(d3使用弧度绘制)
//(6)为组中每个元素添加文本
arcs.append("text")//每个g元素都追加一个path元素用绑定到这个g的数据d生成路径信息
.attr("transform",function(d){
return "translate("+arc.centroid(d)+")";//计算每个弧形的中心点(几何中心)
})
.attr("text-anchor","middle")
.style("fill","white")
.style("font-size","20px")
.text(function(d){
return d.value;//这里已经转为对象了
});
</script>
</body>
</html>
图21
10、地图
10.1、简介:
对于地图的可视化,D3有一些显示和操作地理数据的组件。这些组件使用GeoJSON格式的数据,这是javascript中表示地理特征的标准方法。
10.2、demo:
图2210.3、代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body{ background-color: #000000; }
</style>
</head>
<body>
<script src="../../d3.js"></script>
<script>
var width = 1360, height = 670;
var svg = d3.select("body").append("svg") .attr("width", width) .attr("height", height);
var color=d3.scale.category20c();
var projection = d3.geo.mercator() .center([120, 35]) .scale(540);
var path = d3.geo.path() .projection(projection); d3.json("china.json", function(error, china) { svg.selectAll("path") .data( china.features ) .enter() .append("path") .attr("d",path) .attr("fill","midnightblue");
svg.selectAll("circle") .data(china.features) .enter() .append("circle") .attr("transform", function(d) { return "translate(" + path.centroid(d) + ")"; }) .attr("r", 3 ) .attr("fill",function(d,i){ return color(i)}); });
//添加南海诸岛示意图
//此图截自Echarts:http://echarts.baidu.com/doc/example/map9.html svg.append("svg:image") .attr("xlink:href","southchinasea.png") .attr({ x:550, y:350, "width":50, "height":70 });
</script> <
/body>
</html>
结语:
实际运用中经常同时利用多种布局方法做一个工程。我学习的经验是先去网上找一些demo,比如官网上,下载工程到本地,先跑起来,能在本地展示出效果,然后再去读代码,理解代码,然后修改代码。当然,首先自己本地得先配置好本地服务器,个人举得xampp不错,安装也是傻瓜式地一步下一步。官网的API写得有点不太好读,如果想详细了解d3的API可以参考书籍《D3API详解》。
网友评论