上一節我們已經學習了如何設置填充區域,其實理解了他的實現原理還是非常簡單了。這一節中, 我們主要學習多條曲線的繪制,以及給不同的曲線指定不同的縱坐標。
新的數據
由於我們要畫兩條曲線,所以我們要在原來的基礎上新增一組測試數據,現在我們的數據是這樣的:
date close open
1-May-12 58.13 3.41
30-Apr-12 53.98 4.55
27-Apr-12 67.00 6.78
26-Apr-12 89.70 7.85
25-Apr-12 99.00 8.92
24-Apr-12 130.28 9.92
23-Apr-12 166.70 10.13
20-Apr-12 234.98 12.23
19-Apr-12 345.44 13.45
18-Apr-12 443.34 16.04
17-Apr-12 543.70 18.03
16-Apr-12 580.13 21.02
13-Apr-12 605.23 22.34
12-Apr-12 622.77 20.15
11-Apr-12 626.20 21.26
10-Apr-12 628.44 31.04
9-Apr-12 636.23 35.04
5-Apr-12 633.68 41.02
4-Apr-12 624.31 43.05
3-Apr-12 629.32 46.03
2-Apr-12 618.63 51.03
30-Mar-12 599.55 53.42
29-Mar-12 609.86 57.82
28-Mar-12 617.62 59.01
27-Mar-12 614.48 56.03
26-Mar-12 606.98 58.01
我們把data-close作為一個數據集,把data-open作為一個數據集。現在我們把這些數據存在文件data2.tsv中,並將文件導入:
//Get the data
d3.tsv("../data/data2.tsv", function(error, data){
data.forEach(function(d){
d.date = parseDate(d.date);
d.close = +d.close;
d.open = +d.open;
});
在這里需要注意的是,記得要做一個數據的轉換,確保d.open中存儲的是一個數字!
定義新的曲線
像前面定義曲線一樣,我們定義第二天曲線的時候完全可以按照定義第一條曲線的方法進行定義:
//定義線條2
var valueline2 = d3.svg.line()
.interpolate("basis")
.x(function(d){ return x(d.date) })
.y(function(d){ return y(d.open) });
繪制新的曲線
為了區別於第一條曲線,我們給新的曲線添加一個樣式,把它變成搶眼的紅色:
//繪制線條2
svg.append("path")
.attr("class", "line")
.style("stroke", "red")
.attr("d", valueline2(data));
改進
雖然我們已經把圖形繪制出來,但是,我們的代碼還是不完善的,比方說,如果我的d.open有個值非常非常大,他比d.close中的任何一個值都要大很多,那么我們圖形繪制出來會變成什么效果呢?
紅色線條是不是跑到畫布外面去了!也就是說我們的畫布已經無法容納這個最大的d.open值了,因為我們之前設置y軸的規模(domain)時用的是d.close的最大值:
y.domain([0, d3.max(data, function(d){
return d.close;
})]);
所以,我們要對它進行一個改進,我們要取兩組值中的最大值:
y.domain([0, d3.max(data, function(d){
return Math.max(d.close, d.open);
})]);
兩條縱坐標軸
仔細觀察原來的數據,我們會發現,d.open的值相對於d.close的取發展趨勢更加平穩。但是,如果我們要更好的體現它的細節(也就是把趨勢放大)的話改怎么做呢?很簡單,給他們設置不同的坐標軸!
//定義坐標軸的范圍
var x = d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
var y2 = d3.scale.linear().range([height, 0]);
y跟y2的范圍(也就是像素高)應該是一樣的。我們把y2的tick標簽放在右邊,這樣看起來會更對稱:
//定義坐標軸
var xAxis = d3.svg.axis().scale(x).orient("bottom").ticks(5);
var yAxis = d3.svg.axis().scale(y).orient("left").ticks(5);
var y2Axis = d3.svg.axis().scale(y2).orient("right").ticks(5);
現在,我們還需要修改一下我們的valueline,讓valueline2使用y2作為縱軸方向的基准:
//定義線條1
var valueline = d3.svg.line()
.interpolate("basis")
.x(function(d){return x(d.date);})
.y(function(d){return y(d.close);});
//定義線條2
var valueline2 = d3.svg.line()
.interpolate("basis")
.x(function(d){ return x(d.date) })
.y(function(d){ return y2(d.open) });
同時,我們還要給他們設置不同的規模:
//Scale(規模) the range of the data
x.domain(d3.extent(data, function(d){
return d.date;
}));
y.domain([0, d3.max(data, function(d){
return d.close;
})]);
y2.domain([0, d3.max(data, function(d){
return d.open;
})]);
最后,我們再來繪制它們!
//繪制x坐標軸
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
//繪制y坐標軸
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
//繪制y2坐標軸
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + width + ", 0)")
.style("fill", "red")
.call(y2Axis);
下一節,我們將學習如何x軸的tick標簽很多的情況下,如何旋轉標簽,使他們更便於閱讀!