本节书摘来自异步社区《JavaScript数据可视化编程》一书中的第1章第1.2节作者 【美】Stephen A.Thomas 译者 翟东方 , 张超 , 刘畅 责编 陈冀康更多章节内容可以访问云栖社区“异步社区”公众号查看。
1.2 用折线图来绘制连续数据
柱状图这种形式对于处理一般数据来说已经游刃有余了但是对于更大的数据量使用折线图也许更有效。折线图尤其擅长于展现数据整体趋势避免让用户过于关注个别的数据点而忽略了整体。
在下面的例子中我们会看到两组数据——二氧化碳在大气中的浓度和全球气温。我们怀疑这两组数据之间存在着一定的相关性。我们想要同时展示这两个测量值在过去一段时间里的变化并且试图找到它们之间可能存在的内在联系。对于呈现这些趋势来说折线图是完美的可视化工具。
和柱状图一样你需要先在你的网页中引入Flotr2库然后创建一个
**
1.2.1 第1步 定义数据**
首先我们来处理一下二氧化碳浓度的测量数据。我们使用的是美国国家海洋和大气管理局NOAA从1959年至今发布的夏威夷的莫纳罗亚活火山的测量数据。下面展示的只是从中节选的一些值。
var co2 = [
[ 1959, 315.97 ],
[ 1960, 316.91 ],
[ 1961, 317.64 ],
[ 1962, 318.45 ],
// Data set continues...
NOAA还发布了全球地表平均温度的测量值。这些数据代表的是某一年的平均温度和整个20世纪的平均温度之间的差异。因为我们的二氧化碳测量值是从1959年开始统计的所以我们也同样把温度数据的起点设为1959年。
var temp = [
[ 1959, 0.0776 ],
[ 1960, 0.0280 ],
[ 1961, 0.1028 ],
[ 1962, 0.1289 ],
// Data set continues...
1.2.2 第2步 绘制二氧化碳数据的图像
用Flotr2绘制一个数据集是非常容易的。我们只要简单地调用Flotr对象的draw()方法就可以了。这个方法只有两个必需参数一个容纳图表的HTML元素以及数据本身。
数据对象的lines属性表明了我们想要的是一个折线图。
Flotr.draw(
document.getElementById("chart"),
[{ data: co2, lines: {show:true} }]
);
因为Flotr2不需要依赖jQuery我们在这个例子中没有用jQuery的$等操作符来进行操作。如果你的页面已经包含了jQuery也可以使用jQuery方法来改写上面的代码。无论用哪种方式图表的展示结果应该和图1-6是一样的。
这个图表清晰地展示了过去50年二氧化碳浓度变化的趋势。
1.2.3 第3步 添加温度数据
现在我们只要在代码中把气温的测量数据添加进来就可以了。
Flotr.draw(
document.getElementById("chart"),
[
{ data: co2, lines: {show:true} },
{ data: temp, lines: {show:true}, yaxis: 2 }
]
);
需要注意的是我们的温度数据还包含了一个yaxis参数并且将值设为了2。这就告诉了Flotr2对温度数据使用第2条纵轴的刻度。
图1-7中同时显示了两种测量数据。但还存在一些可能会带来困扰的地方。比如当有多个纵轴时你很难向用户解释网格线和纵轴数字的对应关系。
**
1.2.4 第4步 改进图表的可读性**
通过配置更多的Flotr2属性和参数我们可以把折线图的可读性进一步提升。首先我们可以消除网格线因为它们和温度测量值没有关系。
我们也可以为draw()方法添加一些属性来优化图表两边纵轴的数字范围。
Flotr.draw(
document.getElementById("chart"),
[
{ data: co2, lines: {show:true} },
{ data: temp, lines: {show:true}, yaxis: 2 }
],{
1 grid: {horizontalLines: false, verticalLines: false},
yaxis: {min: 300, max: 400},
2 y2axis: {min: -0.15, max: 0.69}
}
) ;
上面的代码中首先我们在标记为的地方添加了grid属性并把horizontallines和verticallines两个二级属性的属性值设为false这样就关闭了网格线。然后我们在标注2的地方设置了yaxis属性的minimum和maximum两个值代表二氧化碳浓度范围。最后我们在标注的地方设置了y2axis属性即温度的值的纵轴取值范围。
结果如图1-8所示图表变得更加清晰和易读。
1.2.5 第5步 让用户理解右侧的温度标记
右侧纵轴上的温度标记可能会对用户造成困扰因为这些数字并不是实际的温度其代表的是和20世纪平均温度之间的温度差异。我们最好能添加一根代表20世纪平均温度的水平线来作为参考这样就能有效消除用户的疑虑。
我们使用的方法是创建一个虚拟的数据集并添加到图表中。这个数据集中只包含一个值0。
var zero = [];
for (var yr=1959; yr<2012; yr++) { zero.push([yr, 0]); };
当我们添加数据集到图表中时我们要声明这个数据集要对应右侧的纵轴。另外因为我们想让这条线当做图表框架的一部分出现而不是另外一个数据集出现。所以我们可以通过把它设置成宽1像素深灰色没有阴影来降低它的重要程度。
Flotr.draw(
document.getElementById("chart"),
[
{ data: zero, lines: {show:true, lineWidth: 1}, yaxis: 2,
shadowSize: 0, color: "#545454" },
{ data: co2, lines: {show:true} },
{ data: temp, lines: {show:true}, yaxis: 2 }
],{
grid: {horizontalLines: false, verticalLines: false},
yaxis: {min: 300, max: 400},
y2axis: {min: -0.15, max: 0.69}
}
);
正如你看到的我们首先在数据集中放置了一个数值为0的刻度线。由此执行代码后Flotr2就会在0刻度线上面一层绘制实际的数据就和图1-9展示的一样Flotr2会将0刻度线强调为图表框架中的角色而不是把它当作数据来显示。
1.2.6 第6步 给图表添加标注
在这个例子的最后一步我们将会给图表添加适当的标注。标注不仅包含所有的标题也包含每个独立的数据集。同时为了使温度轴上的数字标记易于理解我们还会给温度的刻度添加一个“℃”摄氏度的后缀。
为每组数据添加标注使用的是label属性。图表的标题我们用title属性来标注然后我们使用tickFormatter()函数来添加“℃”后缀。
Flotr.draw(
document.getElementById("chart"),
[ {
data: zero,
label: "20<sup>th</sup>-Century Baseline Temperature",
lines: {show:true, lineWidth: 1},
shadowSize: 0,
color: "#545454"
},
{
data: temp,
label: "Yearly Temperature Difference (°C)",
lines: {show:true}
},
{
data: co2,
yaxis: 2,
label: "CO<sub>2</sub> Concentration (ppm)",
lines: {show:true}
}
],
{
title: "Global Temperature and CO<sub>2</sub> Concentration (NOAA Data)",
grid: {horizontalLines: false, verticalLines: false},
y2axis: {min: -0.15, max: 0.69,
1 tickFormatter: function(val) {return val+" °C";}}
yaxis: {min: 300, max: 400},
}
) ;
tickFormatter属性会遍历对应轴上的每一个标记值并对其进行格式化处理。如你在代码1处所见我们很轻松就在原标记的后面添加了一个“℃”字符。
另外不知道你注意到没有我们在上面的代码中交换了二氧化碳和温度这两个图像之间的位置。我们在新代码中先传递了温度数据temp之后传递二氧化碳数据CO2。这样做的好处是让两个温度标记—20世纪平均温度和每年的平均温度—在图例里能挨在一起让用户更容易明白它们之间的联系。
且因为温度首先出现在图例中我们也可以替换坐标轴将左侧改为温度的坐标。最终我们基于相同理由调整图表的标题。图1-10展现了最终结果。
图1-10所示的是线形图它最擅长于表现这种数据类型的可视化图表。每个数据集包含了超过50个点很难将每一个点呈现出来。实际上单个数据点不是可视化要关注的。我们其实是想要展现趋势——每一个数据集的趋势以及数据集之间的相关性。把这些点用线串连起来以引导用户获取正确的趋势这才是可视化的核心价值。
1.2.7 第7步Flotr2“bugs”的应急方案
可以参考本书1.1.9小节了解如何解决Flotr2类库的一些“bug”的。