《JavaScript数据可视化编程》——1.5 用气泡图表示数量扩展x/y数据

简介:

本节书摘来自异步社区《JavaScript数据可视化编程》一书中的第1章,第1.5节,作者: 【美】Stephen A.Thomas 译者: 翟东方 , 张超 , 刘畅 责编: 陈冀康,更多章节内容可以访问云栖社区“异步社区”公众号查看。

1.5 用气泡图表示数量扩展x/y数据

像前面例子描述的传统离散型图表,只能展现x和y轴两个值之间的关系。有时两个值并不能恰当的展现出我们想要展现的数据。如果我们需要3个变量,我们可以使用一个离散型图表的框架来展现两个值,然后根据第三个值来改变图表中点的大小。那么使用气泡图就是最好的选择。

然而在使用气泡图时有一些需要注意的。像我们早先看到的饼图一样,人们非常不善于准确判断一个不是长方形形状的相对区域,所以气泡图不能让人们准确对比气泡的大小。但是,如果你只想展现一个大概的量而不是准确的量,那么使用气泡图是适合的。

在这次的例子中我们使用气泡图展现2005年卡特里娜飓风的路径。我们的x和y轴将会代表位置(纬度和经度),并且我们要确保我们的用户能准确地理解这些值。对于第3个值-气泡的大小-我们将使用风暴的持续风力,因为风速永远只是一个普通数值(并且风有时候大有时候小),所以使用持续风力是合适的。

就像本书1.1.1小节中一样,我们需要在我们的网站中包含Flotr2的类库,并且设置一个div元素来包含我们将要创建的图表。

1.5.1 第1步 定义数据
我们使用美国国家海洋和天气管理局(NOAA)的卡特里娜飓风的观察报告来做我们例子的数据。数据包括了飓风行进时的经纬度和每小时的风速。

var katrina = [
    { north: 23.2, west: 75.5, wind:  35 },
    { north: 24.0, west: 76.4, wind:  35 },
    { north: 25.2, west: 77.0, wind:  45 }, 
    // Data set continues...

对于气泡图,Flotr2需要每个数据点是一个数组而不是一个对象,所以我们要建立一个简单的函数将源数据转换成需要的格式。为了使函数更通用,我们可以传参指定一个过滤函数。当我们提取数据点时,我们可以反转经线符号从左到右显示由西向东。

function get_points(source_array, filter_function) { 
1   var result = [];
     for (var i=0; i<source_array.length; i++) { 
         if ( (typeof filter_function === "undefined")
           || (typeof filter_function !== "function") 
           || filter_function(source_array[i]) ) { 
             result.push([
                 source_array[i].west * -1,
                 source_array[i].north,
                 source_array[i].wind
            ]);
         }
     }
     return result;
 }

我们这段代码一开始在1的位置设置了一个返回值(result),是一个空数组。然后循环source_array,每次输入一个元素。如果filter_function参数是可用的,并且如果它是有效的函数,我们的代码会把源数组中当前元素作为参数在这个函数中进行调用。如果函数返回true,或者如果在get_points函数一开始的时候没有传filter_function函数参数,我们的代码会从源数组中的各个元素提取数据点然后push到result数组中。

正如你所看到的,filter_function参数是可选的。如果调用方省略它(或者不是一个有效的函数),那么在result中就是源的每个数据点。虽然我们现在并不马上使用过滤函数,但在这个例子后面的步骤中,我们就可以拿来就用了。

1.5.2 第2步 给图表创建背景图
因为我们图表中x和y轴的值表示的是坐标,用地图当作背景是再合适不过的了。为了避免涉及到版权的问题,我们使用stamen设计网站上的地图图片,使用OpenStreetMap网站的数据。这两者分别在Creative Commons CC 3.0和CC SA授权下可用。

当你使用地图时投影就成了棘手的问题,除了映射的地区更小以外,缺少有效的映射也是个问题,映射的地区都在图表中心的边缘。对于这个例子,我们将采取墨卡托投影来展示地图,在相对小的区域聚焦。假设我们已经将x、 y轴和经纬度进行了转换。

图1-21展示了将被我们用来覆盖飓风路径的地图。
screenshot

1.5.3 第3步 绘制数据
一开始我们还是先从使用最少选项开始写代码,尽管这样我们需要迭代几次才能得到想要的图表。我们需要一个参数来指定气泡的半径。对于像这个例子中的静态图表,最简单的方法就是用几个值尝试找出最合适的尺寸。在我们的例子中使用了0.3这个值。除了前面的选项以外, draw方法还需要一个包含图表的HTML元素和数据本身。

Flotr.draw( 
    document.getElementById("chart"), 
    [{ 
        data: get_points(katrina),
        bubbles: {show:true, baseRadius: 0.3} 
    }]
);

正如你所看到的,我们使用了前面写的转换函数来从源数据中提取需要的数据。这个函数的返回值直接被传递到draw方法的第二个参数中。

目前,我们还不用操心背景图片的问题。我们只需要把调整过的数据添加到图表中就可以了。图1-22中就是目前为止显示的效果,尽管还需要改进,但我们已经迈出了第1步。

screenshot

1.5.4 第4步 添加背景
现在我们来看一下Flotr2是如何在背景图上绘制数据的。同时我们还想要做一些别的事情。首先我们添加一个背景图,移除掉网格线。其次,不显示轴线的标注;经纬线对于普通用户来说没有什么意义,地图对于用户来说也不是必需的。最后,也是最重要的,我们需要调整缩放图表来匹配地图图片。

Flotr.draw(
     document.getElementById("chart"), 
     [{ 
       data: get_points(katrina), 
       bubbles: {show:true, baseRadius: 0.3} 
     }],
     {
1        grid: {
             backgroundImage: "img/gulf.png", 
             horizontalLines: false, 
             verticalLines: false
         },
2        yaxis: {showLabels: false, min: 23.607, max: 33.657}, 
3         xaxis: {showLabels: false, min: -94.298, max: -77.586}
     }
 );

我们在1的位置添加了一个grid的选项来告诉Flotr2不展示横纵网格线,并且指派一个用背景图片代替。我们想要图片展示的纬度值从23.607°N到33.657°N,经度值从77.568°W到94.298°W。所以在2和3的位置我们将这些值提供给xaxis和yaxis选项来当作的范围值,并且将两个轴的标注设置为不显示。需要注意的是因为我们涉及到的经度是西经,所以需要使用负值。

在图1-23中看图表这些点效果还不错。我们不仅可以清楚的看到飓风的路径还能看到飓风的强弱变化。

screenshot

1.5.5 第5步 给气泡上色
在这个例子中,我们通过选项来修改气泡的颜色,可以让用户不用过于耗费精力就能获取到更多的信息。让我们在每个观察点上加上能表明萨菲尔-辛普森飓风等级的数字。

这里我们可以利用我们前面做的数据格式化函数来过滤一下要展现的数字。因为萨菲尔-辛普森飓风等级是基于风速的,所以我们要基于风的属性来过滤。例如下面的代码展现了只将风速74英里/小时到95英里/小时的值提取出来作为1级飓风等级。我们传给get_points函数的是返回为true的风速。

cat1 = get_points(katrina, function(obs) {
    return (obs.wind >= 74) && (obs.wind < 95);
});

我们用下面的代码来将数据划分到多个集合中,让Flotr2来分配不同的颜色给每个集合。除了5级飓风以外,我们已经解析出了热带风暴和热带气压的强度。

Flotr.draw( 
    document.getElementById("chart"), 
    [
      {
          data: get_points(katrina, function(obs) {
                    return (obs.wind < 39);
                }),
          color: "#74add1",
          bubbles: {show:true, baseRadius: 0.3, lineWidth: 1}
       },{ 
       // Options continue...
       },{
         data: get_points(katrina, function(obs) {
                   return (obs.wind >= 157);
               }),
         color: "#d73027",
         label: "Category 5",
         bubbles: {show:true, baseRadius: 0.3, lineWidth: 1}
       }
     ],{ 
       grid: {
           backgroundImage: "img/gulf.png",
           horizontalLines: false, 
           verticalLines: false
       },
       yaxis: {showLabels: false, min: 23.607, max: 33.657},
       xaxis: {showLabels: false, min: -94.298, max: -77.586},
       legend: {position: "sw"}
     }
);

如你在图1-24中看到的,我们在左下角已经给飓风等级添加了标注和图例。

screenshot

1.5.6 第6步 调整图例的样式
默认情况下,Flotr2会让所有元素看起来都尽可能的大。在图1-24中的图例就是一个好例子:它看起来很局促且不够吸引人。幸运的是,修改这个很简单:我们简单添加一些CSS的padding样式就可以了,我们也可以设置图例的背景颜色来和Flotr2的背景形成反差来突出。

.flotr-legend {
   padding: 5px;
   background-color: #ececec; 
}
为了防止Flotr2给图例创建背景色,我们将透明度设置为0。

Flotr.draw( 
    document.getElementById("chart") 
        // Additional options...
        legend: {position: "sw", backgroundOpacity: 0,}, 
        // Additional options...

经过最后的调整,图1-25就是我们最终完成的样子。我们不想使用Flotr2的选项来指定标题,因为Flotr2将标题等也算在图表内容区内,所以当字数较多时,会将图表空间压缩收窄(并且我们也不能预知用户浏览器的字体大小)。这会导致纬度的变形。所以简单的用HTML标签来盛放标题就可以了。

screenshot

气泡图相比二维的离散图表增加了其他维度。事实上,和我们的例子一样,它也可以进一步添加两个维度。在例子中使用气泡尺寸来代表风速,颜色表明飓风的分类。这两个值都需要关注。人们既不善于对比两个维度的区域,也不能轻松的对比相对的形状和颜色。气泡图从来都不应该用来表达一个临界数据或精确的数量。在例子中气泡图表现的很好,既不用准确的表示风速,也不用精确的指定飓风的位置。几乎没有人能区分出100/小时和110米/小时的差别,但他们能知道达拉斯和奥尔良的区别。

1.5.7 第7步 Flotr2“bugs”的应急预案
请参考本书1.1.9小节中关于创建基本柱状图表中是如何解决Flotr2类库的一些“bug”的。

相关文章
|
7月前
|
Web App开发 数据采集 JavaScript
动态网页爬取:Python如何获取JS加载的数据?
动态网页爬取:Python如何获取JS加载的数据?
1225 58
|
JavaScript 前端开发
js实现数据的双向绑定
js实现数据的双向绑定
311 59
|
JavaScript 算法 前端开发
采招网JS逆向:基于AES解密网络数据
采招网JS逆向:基于AES解密网络数据
313 0
|
9月前
|
数据采集 JavaScript 前端开发
JavaScript中通过array.filter()实现数组的数据筛选、数据清洗和链式调用,JS中数组过滤器的使用详解(附实际应用代码)
用array.filter()来实现数据筛选、数据清洗和链式调用,相对于for循环更加清晰,语义化强,能显著提升代码的可读性和可维护性。博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
机器学习/深度学习 JavaScript Cloud Native
Node.js作为一种快速、可扩展的服务器端运行时环境
Node.js作为一种快速、可扩展的服务器端运行时环境
213 8
|
开发框架 JavaScript 前端开发
TypeScript 是一种静态类型的编程语言,它扩展了 JavaScript,为 Web 开发带来了强大的类型系统、组件化开发支持、与主流框架的无缝集成、大型项目管理能力和提升开发体验等多方面优势
TypeScript 是一种静态类型的编程语言,它扩展了 JavaScript,为 Web 开发带来了强大的类型系统、组件化开发支持、与主流框架的无缝集成、大型项目管理能力和提升开发体验等多方面优势。通过明确的类型定义,TypeScript 能够在编码阶段发现潜在错误,提高代码质量;支持组件的清晰定义与复用,增强代码的可维护性;与 React、Vue 等框架结合,提供更佳的开发体验;适用于大型项目,优化代码结构和性能。随着 Web 技术的发展,TypeScript 的应用前景广阔,将继续引领 Web 开发的新趋势。
335 2
|
监控 JavaScript 算法
深度剖析 Vue.js 响应式原理:从数据劫持到视图更新的全流程详解
本文深入解析Vue.js的响应式机制,从数据劫持到视图更新的全过程,详细讲解了其实现原理和运作流程。
|
前端开发 JavaScript 应用服务中间件
Nginx 支持 JavaScript:前所未有的扩展
Nginx 是全球领先的高性能 Web 服务器,以其高效的反向代理和负载均衡功能著称。近期,Nginx 正式支持 JavaScript(通过 NJS 模块),基于 V8 引擎,允许在配置中嵌入 JS 代码,极大提升了灵活性和扩展性。开发者可以使用 JavaScript 实现动态请求处理、自定义认证、复杂响应处理、中间件编写及流量控制等功能,显著降低开发和维护难度,同时保持高性能。NJS 模块的引入为 Nginx 带来了前所未有的扩展能力,适应快速变化的业务需求。
359 0
|
数据采集 存储 JavaScript
如何使用Puppeteer和Node.js爬取大学招生数据:入门指南
本文介绍了如何使用Puppeteer和Node.js爬取大学招生数据,并通过代理IP提升爬取的稳定性和效率。Puppeteer作为一个强大的Node.js库,能够模拟真实浏览器访问,支持JavaScript渲染,适合复杂的爬取任务。文章详细讲解了安装Puppeteer、配置代理IP、实现爬虫代码的步骤,并提供了代码示例。此外,还给出了注意事项和优化建议,帮助读者高效地抓取和分析招生数据。
509 0
如何使用Puppeteer和Node.js爬取大学招生数据:入门指南
|
前端开发 JavaScript
JS-数据筛选
JS-数据筛选
135 7

热门文章

最新文章