d3入门

很久很久之前就了解过D3,但是一直没有着手开始学习。最近感觉之前的学习遇到瓶颈,进步不大,就又把D3拿出来学习了。

首先D3的官网:http://d3js.org/

中文学习网站:http://www.ourd3js.com/wordpress/


d3(data-driven documents)其实就是一个js库,可以用来把数据搞成图,官方的话就是把数据绑定到DOM元素上。d3js中有很多超级炫酷的例子。

接下来就简单介绍一下最近学习的几个画图的方法。


一 曲线图

在这之前说一下d3的使用,就是要引入一个js。注意!!这个js一定要放在自己写的d3js之前,js的执行是顺序的!我就在这里被自己蠢到了。

先上代码。

<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<link rel="stylesheet" type="text/css" href="css/style.css" media="screen">
	<title>D3</title>
</head>
<body>
	<div id = "container"></div>
	 <script src="js/d3.v3.js"></script>
     <script src="js/line.js"></script>

</body>
</html>
在html中给出一个容器,用来盛放d3的svg就好了。要引入d3js。

画图用d3的函数来完成。

var width = 500,
height = 250,
margin = {left:50,top:30,right:20,bottom:20},
g_width = width - margin.left - margin.right,
g_height = height - margin.top - margin.bottom;

//svg  
var svg = d3.select("#container")   //选中container
.append("svg:svg")         //添加svg元素
//width,height
.attr("width",width)
.attr("height",height)

var g = d3.select("svg")
.append("g")
.attr("transform","translate(" + margin.left+"," + margin.top +")")   //g元素的偏移

var data = [1,3,5,7,8,4,3,7]

var scale_x = d3.scale.linear()    //横向伸缩
.domain([0,data.length-1])    //输入范围
.range([0,g_width])           //输出范围
var scale_y = d3.scale.linear()    //纵向伸缩
.domain([0,d3.max(data)])
.range([g_height,0])   //倒着写是为了让纵坐标在显示的时候是从下往上增大的(因为浏览器的左边原点在左上而数学习惯是在左下)

var line_generator = d3.svg.line()   //d3的svg下的line函数
.x(
	function(d,i){
		return scale_x(i);
})  //x坐标点可以用数组data的下标来表示
.y(
	function(d){
		return scale_y(d);
})  //用数组实际的值
.interpolate("cardinal")   //指定拟合方式

d3.select("g")
.append("path")
.attr("d",line_generator(data))  
//d="M1,0L20,40L40,50L100,100L0,200"  d代表path data M代表起点,坐标(1,0),L代表直线,后面的数字是拐点
//line_generator是我们定义的一个函数

var x_axis = d3.svg.axis().scale(scale_x),
y_axis = d3.svg.axis().scale(scale_y).orient("left");  //确定方向是在左边

g.append("g")
.call(x_axis)
.attr("transform","translate(0,"+g_height+")")  //偏移

g.append("g")
.call(y_axis)
.append("text")
.text("Price($)")
.attr("transform","rotate(-90)")   //旋转-90°
.attr("text-anchor","end")
.attr("dy","1em")

代码都有注释就不详细解释了,看一下效果:



二 面积图

面积图就是在曲线图的基础上,用曲线和x轴围出一个闭合的图形,然后填色就对了。

var width = 500,
height = 250,
margin = {left:50,top:30,right:20,bottom:20},
g_width = width - margin.left - margin.right,
g_height = height - margin.top - margin.bottom;

//svg  
var svg = d3.select("#container")   //选中container
.append("svg:svg")         //添加svg元素
//width,height
.attr("width",width)
.attr("height",height)

var g = d3.select("svg")
.append("g")
.attr("transform","translate(" + margin.left+"," + margin.top +")")

var data = [1,3,5,7,8,4,3,7]

var scale_x = d3.scale.linear()    //横向伸缩
.domain([0,data.length-1])    //输入范围
.range([0,g_width])           //输出范围
var scale_y = d3.scale.linear()    //纵向伸缩
.domain([0,d3.max(data)])
.range([g_height,0])   //倒着写是为了让纵坐标在显示的时候是从下往上增大的

var area_generator = d3.svg.area()   //生成面积的函数
.x(
	function(d,i){
		return scale_x(i);
})  //x坐标点可以用数组data的下标来表示
.y0(
	g_height
)  //y0是x轴
.y1(
	function(d){
		return scale_y(d);
})  //y1是那条曲线
.interpolate("cardinal")   //指定拟合方式

d3.select("g")
.append("path")
.attr("d",area_generator(data))  
//d="M1,0L20,40L40,50L100,100L0,200"  d代表path data M代表起点,坐标(1,0),L代表直线,后面的数字是拐点
//line_generator是我们定义的一个函数
.style("fill","steelblue")

var x_axis = d3.svg.axis().scale(scale_x),
y_axis = d3.svg.axis().scale(scale_y).orient("left");  //确定方向是在左边

g.append("g")
.call(x_axis)
.attr("transform","translate(0,"+g_height+")")

g.append("g")
.call(y_axis)
.append("text")
.text("Price($)")
.attr("transform","rotate(-90)")
.attr("text-anchor","end")
.attr("dy","1em")


三 柱状图

这里画柱状图用了两种方法,一种是设定柱状图的长宽和间隔,然后将数据绑定到元素上,生成柱状图。另一种是用ordinal()函数来实现柱状图在x轴的伸缩。(教程里还讲了水平柱状图和竖直柱状图,原理是差不多的,这里只讲竖直的柱状图。)

1.设定长宽间隔来生成柱状图

d3.csv("data.csv",type,function(data){
	console.log(data);   //读取csv文件作为画图的数据

var bar_width = 50,
bar_padding = 10,
svg_width = (bar_width + bar_padding)*data.length,
svg_height = 500;

var scale = d3.scale.linear()
.domain([0,d3.max(data,function(d){return d.population;})])
.range([svg_height,0]);    //因为屏幕的坐标原点在左上,所以这里为了符合我们的习惯(坐标原点在左下),输出范围是从大到0

var svg = d3.select("#contain")
.append("svg")
.attr("width",svg_width)
.attr("height",svg_height)


var bar = svg.selectAll("g")   //选择还不存在的g元素
.data(data)   //绑定数据
.enter()   //enter选中只有数据没有元素的selection
.append("g")
.attr("transform",function (d,i) {
	return "translate("+i*(bar_width+bar_padding)+",20)";  //这里注意Y轴偏移20是为了把标注的数字可以放在画布里,不然是放不下数字的
})


bar.append("rect")  //生成矩形
.attr({
	"y":function(d) {return scale(d.population);},
	"height":function(d) {return svg_height - scale(d.population);},
	"width":bar_width
})
.style("fill","steelblue")

bar.append("text")
.text(function(d){return d.year;})
.attr({
	"y":function(d){return scale(d.population);},
	"x":bar_width/2,
	"text-anchor":"middle"
})

})

//将字符串转换为数值的形式
function type(d){
	d.population =+ d.population;
	return d;
}

这里注意到一点,这次画图的数据是导入了一个csv文件,而不是我们指定的数据。

csv格式的数据其实是一种纯文本的数据。

这里注意,读出的csv文件是字符串形式的,需要我们用函数将其转换为数值的形式。

并且,csv是有作用范围的。要将d3画图的内容都包裹在csv的作用范围内。


2 用ordinal()函数来生成柱状图

d3.csv("data.csv",type,function(data){
	console.log(data);

var width = 1000,
height = 500,
margin = {left:30,top:30,right:30,bottom:30},
svg_width = width + margin.left + margin.right,
svg_height = height + margin.top + margin.bottom;

var scale = d3.scale.linear()  //延y轴的缩放
.domain([0,d3.max(data,function(d){return d.population;})])
.range([height,0]);    //因为屏幕的坐标原点在左上,所以这里为了符合我们的习惯(坐标原点在左下),输出范围是从大到0

var scale_x = d3.scale.ordinal()  //延x轴的延伸
.domain(data.map(function(d){return d.year;}))
.rangeBands([0,width],0.1);

var svg = d3.select("#contain")
.append("svg")
.attr("width",svg_width)
.attr("height",svg_height)

var chart = svg.append("g")
.attr("transform","translate("+margin.left+","+margin.top+")");

var x_axis = d3.svg.axis().scale(scale_x),
y_axis = d3.svg.axis().scale(scale).orient("left");   //定义X轴Y轴

chart.append("g")
.call(x_axis)
.attr("transform","translate(0,"+height+")");
chart.append("g")
.call(y_axis);    //添加X轴Y轴

var bar = chart.selectAll(".bar")
.data(data)
.enter()
.append("g")
.attr("class","bar")  //因为上面xy轴用到了g,而这里选择g就会造成混乱,所以要给g加一个class为"bar",以示区分
.attr("transform",function (d) {
	return "translate("+scale_x(d.year)+",0)";
})

bar.append("rect")
.attr({
	"y":function(d) {return scale(d.population);},
	"height":function(d) {return height - scale(d.population);},
	"width":scale_x.rangeBand()
})
.style("fill","steelblue")

bar.append("text")
.text(function(d){return d.population;})
.attr({
	"y":function(d){return scale(d.population);},
	"x":scale_x.rangeBand()/2,
	"text-anchor":"middle"
})

chart.append("g")
.call(y_axis)
.append("text")
.text("人口(亿)")
.attr("transform","rotate(-90)")
.attr("text-anchor","end")
.attr("dy","1em")

})

//将字符串转换为数值的形式
function type(d){
	d.population =+ d.population;
	return d;
}
这里的重点是在ordinal函数https://github.com/mbostock/d3/wiki/Ordinal-Scales#ordinal



四 饼状图

画饼状图就是画扇形,函数是d3.svg.arc(),参数有内外半径和起止的角度。

d3.csv("data1.csv",type,function (data) {

var width = 400,
height = 400;

var svg = d3.select("#contain")
.append("svg")
.attr("width",width)
.attr("height",height);

var g = svg.append("g")
.attr("transform","translate(200,200)");  //设置饼状图的圆心

var arc_generator = d3.svg.arc()   //生成饼状图(扇形)的函数
.innerRadius(80)  //内部的半径
.outerRadius(200)   //外部半径
// .startAngle(0)   //起始角度,竖直上面为0
// .endAngle(120*Math.PI/180);   //结束角度,要转换为极坐标的形式   //这里是为了说明函数才规定了起止角度,实际应用中,角度是根据数据来确定的。

var angle_data = d3.layout.pie()
.value(function(d) {return d.population;})  //数据和角度的联系

console.log(angle_data(data));

var color = d3.scale.category10();  //这里是为了把不同的块设置为不同的颜色

g.selectAll("path")   //选择还不存在的path
.data(angle_data(data))   //把data的数据传进去
.enter()   //通过enter选中只有数据没有元素的selection
.append("path")
.attr("d",arc_generator)
.style("fill",function(d,i){return color(i);})

g.selectAll("text")
.data(angle_data(data))
.enter()
.append("text")
.text(function(d) {return d.data.education;})
.attr("transform",function(d){return "translate("+arc_generator.centroid(d)+")";})   //扇形取中心
.attr("text-anchor","middle");

});

function type(d){
	d.population =+ d.population;
	return d;
}
中间遇到了一个问题,就是本次引入的csv文件中有中文,所以,会存在编码问题。

csv文件的默认编码格式是ANSI编码,而我们用的是utf-8编码,所以在浏览器中就会出问题。

解决办法是,用记事本打开csv文件,然后另存的时候,会有选择编码的选项,选择utf-8就可以在浏览器中正常显示中文。

或者用csv函数本身的编码方式:

var csv = d3.dsv(",", "text/csv;charset=gb2312");
var tsv = d3.dsv(" ", "text/tab-separated-values;charset=gb2312");



以上是D3画基本统计图的方法。


后来看了一个会让图动起来的函数.transition() 

比如把他写在两个颜色中间,就可以实现渐变色的动态效果。

.attr("fill","red")
//下面的代码是实现动态变化
.transition()   //动态
.duration(3000)  //持续时间
.ease("bounce")    //变换方式 
.delay(function(d,i){    //延时
	return 200*i;
})
.attr("fill","steelblue");

或者来实现鼠标交互,就是鼠标放上去会有特效

//下面的代码是实现鼠标交互
.on("click",function(d,i){
				d3.select(this)
				  .attr("fill","green");
		   })
		   .on("mouseover",function(d,i){
				d3.select(this)
				  .attr("fill","yellow");
		   })
		   .on("mouseout",function(d,i){
				d3.select(this)
				  .transition()
		          .duration(500)
				  .attr("fill","red");
		   });



  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值