叙事结构

1.发现故事

本课讲述可视化用到的:
叙事结构
数据收集过程
数据处理

2.新闻方法

给可视化添加语境
围绕数据进行叙事

我们需要使用定量数据和事实支撑我们所断言的东西,传递定性观点
http://fivethirtyeight.com/features/what-the-fox-knows/

3.相关性与因果关系

一般来讲,因果关系的假设力度比相互关系更大
例子:
电影数量增加 // 癌症发生率增加
错误理解事物的关系,会得出误导性结论,基于误导性结论,会得到很严重的后果
即使一个相关性是真实和有意义的,它并不一定说明存在因果关系。

要获取虚假关系的更多示例,请参阅 Tyler Vigen 的虚假相关(Spurious Correlations)。

你还可以查看更多相关性并不意味着因果关系维基百科示例。

如果你想换一个更为轻松的方式证实这个问题,Spurious Correlations 网站 上有更多示例。

4.新新闻主义

传统新闻:
基于叙事的数据
叙事是新闻的重点,数据是辅助和支持
将静态图表嵌入文章支撑文章观点
通过一系列事件传递信息,线性叙事
媒介:报纸、杂志、静态网页

数据新闻:
叙事围绕数据展开
掌握数据集,以此为基础,讲述其中的故事
使用交互式图表,辅以标签、注释、侧边栏等为数据添加语境,围绕图表叙事、讲故事
利用交互性,创造更加复杂多样的叙事结构,使用户发现数据故事,故事结构和叙事丰富多样
开放式网络技术,交互式可视化

5. 数据可视化的难点所在

数据是数据可视化的重要组成部分
90%的工作在于收集数据、验证数据、打包数据、过滤数据、开发数据
可视化是这些工作的最后一步

6. 获取数据

Scott 解释说,创建数据可视化 90% 的时间实际上都花在“寻找、验证、解析、筛选和探索数据”上。在数据科学及尝试回答数据问题的背景下,的确如此。幸运的是,有很多资源可以任你使用,来解决这些重要的任务。

标题文本“获取数据”中的链接包含很多探寻数据的绝妙技巧,我们建议你查阅以下两个章节:五分钟实战指南和从 Web 获取数据。你还可以给“获取数据”资源加上标签,在以后使用。

对于验证数据,了解数据的内外信息完全取决于你,包括数据的来源、收集方式或其他数据生成过程。Scott Murray 将在下一系列的视频中讨论验证数据的一个示例,涵盖客观和主观数据可视化。

如果你之前尝试清理混乱的数据集,你肯定知道数据处理和操作是非常繁杂的。有多个工具,如 OpenRefine、Google Spreadsheets(或 Excel)、iPython Notebook 和 Pandas(示例)以及 R 可帮助你解析数据和获得创建可视化所需的数据。

一旦你获得所需的数据,你就可以开始创建可视化了。在接下来的视频系列中,Chris 将讲解一些常见的误区所在,以及主观数据可视化会如何误导读者。

7. 如何用柱状图撒谎

叙事结构_第1张图片
image.png

Fox News 继续保持卓越绘图,作者:(想表达讽刺的)Nathan Yau
条形图必须有一条零基线,而线型图可以不从零点开始
要让观众明白所传递的信息,不要把细小的差别无限放大,这就需要将语境纳入考虑范围

8. 如何用饼状图撒谎

在 3D 饼图中展示数据的替代方法有哪些?创建一个新设计来展示数据。 在讨论“饼图的替换方法 (Alternatives to Pie Charts)”中分享你的图形的新设计。

把馅饼留作甜点吧(Save the Pies for Dessert) 作者:Stephen Few

了解我们的其他图形改造及有关使用 plot.ly 的更多信息。

叙事结构_第2张图片
image.png

9. 如何用线形图撒谎

我们来看看最后一个示例,了解你如何可能有意无意地用可视化误导你的读者。

Eric Portelance 通过一个示例探究了美国男性的中等收入自 1972 后的下降规律,或者有没有下降。

读完整篇文章需要 5 至 10 分钟。

10. 偏差类型

之前 Cole 和 Matt 分享的数据可视化包含偏差。在构造图形时有三种偏差需要注意:作者偏差、数据偏差和读者偏差。
作者偏差
Cole 和 Matt 的数据可视化包含作者偏差。也就是说,可视化的设计者和呈现者(无意或有意地)通过可视化编码或其他设计选择(如图表类型)篡改了数据。如果你将来想使用三维饼图,请记住 Andy Kriebel 的一句话“真的朋友不会让自己的朋友使用饼图”。
作为数据可视化的设计者或呈现者,你的设计选择应该在读者和图形之间建立信任。你的设计选择应该促进信息的交流。否则就像 Cole 指出的那样,你的信息会在读者中面临整体可信度风险。
数据偏差
在了解数据偏差之前,我们想让你先看一个视频,在这个视频中 Scott 回答了 Cole 和 Matt 的同样问题。但 Scott 用另一种方式解释了他认为什么是“主观”数据可视化。
读者偏差
我们将在几个视频之后讲解这种偏差。

11.个人数据可视化

主观的数据可视化:
Nicolas Felton 的年度报告

《量化人生:自我监控的数据狂人》(A Life in Data: Nicolas Felton's Self Surveillance)

APRILZERO(由 Anand Sharma 创建)

12.数据偏差

数据偏差产生于数据收集过程中。系统测量误差或有缺陷的设备会使原始数据值产生偏差,而选择偏差会导致不能代表特定问题兴趣群体的子组。数据偏差和抽样方法不在此课程的范围之内,但是我们鼓励你多多了解这些话题。你可以阅读一些关于数据收集、抽样方法或其他偏差话题的文章。Scott Murray 将在下一个视频中提及测量误差的一个示例。

13.数据收集中的错误

14.个人数据可视化

技术改变了我们追踪和分享个人数据的方式。手表、手机、客户卡和其他小工具让我们可以每天分享我们的运动、卡路里和消费习惯。在下一个视频中,Scott 分享了不同的个人数据可视化示例,这个示例包含非常私人的信息,捕捉了一个人的生活动态。

15. 一个人类的心跳

一个名为 one human heartbeat的项目
http://onehumanheartbeat.com

16. 读者偏差

我们最后要讲到的偏差类型是读者偏差。读者偏差包括任何读者在解释可视化时带入的先入观念或假设。

此假设可能与读者的领域知识或数据可视化的话题有关。例如,如果你稍微了解世界杯,你就可能清楚这项比赛的举办频率,以及世界杯的比赛和阶段结构。

其他假设还可能涉及政治、宗教、文化信仰或读者对特定图表类型的熟悉程度。在设计可视化时,你应该始终考虑到读者的背景和对图形的熟悉度。

设计者(编码者)和读者(解码者)都应注意偏差。设计者的选择或读者对图形的解读都会影响交流的有效性。这模糊了数据可视化中误导和欺骗的界线,只有运用分析思维和尽职调查,设计者和读者才能进行可信的信息交换。

要获得更多关于作者偏差和读者偏差的示例,请参阅 Mushon Zer-Aviv 的《虚假信息可视化》(Disinformation Visualization)。

17. 叙事结构的不同类型

传统叙事结构:
故事的开头、情节的上升、高潮、最终方案的结尾部分

作者驱动的叙事结构:
明确的开头和结尾
沿着作者给定的线性流发展

观众驱动的叙事结构:
一种强有力的叙事方式,允许用户选择自己的叙事结构
明确的开头,但是作者可让读者自由选择,允许它们选择叙事发展的方向
每个用户的起点相同,但是鉴于他们对数据的理解不同,在叙事中做出的选择不同,结尾会千差万别

视觉叙事/叙事可视化
通过结合交际和探索信息的可视化,来传递故事意图

作者驱动和观众驱动这两种叙事结构常常会落入一个重叠范围,
作者驱动:
探索元素较少的可视化,可有效用于叙事顺序严谨、信息量大,要求清晰度和速度的叙事结构中

观众驱动:
不会明确指定使用特定的叙事结构,而是让观众和数据自由互动,观众可以提出问题、探索故事进展,讲述自己的数据故事
《叙述可视化:用数据讲故事》(Narrative Visualization: Telling Stories with Data) 作者:Edward Segel 和 Jeffrey Heer

18. 作者驱动示例

通过数据集传递特定的叙事结构

叙利亚难民危机可视化(作者:Wesam Manassra)
作者按照严格的时间顺序来告诉观众叙利亚难民在2012-2014年间的逃亡情况

Facebook 首次公募:与其它公司的比较 (The Facebook Offering: How It Compares)(来自《纽约时报》)

19. 读者驱动示例

“旧金山犯罪直击”(San Francisco Crimespotting),由 Stamen Design 创立。
数据过滤器:缩放比例、时间、日期、犯罪类型,读者可自由探索
通过简单的互动,这个可视化使我能够提出对自己来说重要的问题,通过数据集讲述读者自己的故事

白宫之路 (Paths to the White House),来自《纽约时报》
将总述和观众驱动结合在了一起,观众可以通过鼠标操纵,查看各个方面的数据,讲述自己的故事

在 0:28 处,Ryan 说“假设我住在教会区。”这里所说的教会区是旧金山的一个地区。

在 0:32 处,Ryan 提到 BART 站。BART 或湾区捷运系统是一个高速铁路公共交通系统。

20. 马提尼酒杯

作者驱动可视化:
呈线性结构,叙事结构是预先设定好的

观众驱动可视化:
使观众可以与数据进行直接的互动,创造他们自己的故事

第三种叙事结构:马提尼酒杯
用于更加复杂的数据可视化
杯座、细长的杯茎(作者驱动的唯一路径)、开阔的杯口
观众从杯座开始,穿过杯茎,到达杯口后,他们可以自由探索包含在数据里的各种路径,讲述他们自己的故事,这是将作者驱动和读者驱动的叙事结构结合到了一个连贯的整体中。


叙事结构_第3张图片
image.png

21. 无人机空袭和枪击死亡

无人机空袭
结合作者驱动和观众驱动来强化叙事

枪击死亡

22. 叙事总结

对于叙事没有一个万能的方法,选择哪个结构将取决于叙事,并最终取决于数据本身

23. 分析叙事结构

经合组织美好生活指数

评估加沙的损害和破坏

出生年份对政治观点的影响

为何女性薪水较低

评价健康法

大城市的崛起

从一下几个方面分析叙事结构:

  • 图表采用什么可视化叙事方式
  • 可视化如何将你带入这些数据
  • 可视化讲述了一个怎样的故事
  • 如何改善可视化叙事结构

24. 注释和世界杯参赛人数图表

围绕图表标注的语境
确保你创建的图表有:
明确的单位信息/y轴/百万/世界杯观赛人数单位
明确的单位信息/x轴/年份
信息标签/一目了然,不需要任何附加解释
图表标题/有效传递图表的整体信息

补充图表信息:
D3

  • 更加灵活
  • 允许在图表中使用更加复杂的互动和动画

25. 解密D3

库的一个强大功能是:具有声明性语法,即告诉D3你希望实现什么,而不必说如何实现

D3最强大且神秘的一个功能是,它可以通过.data函数执行数据绑定
如果我们在没有圆圈时选择圆圈,那就会返回empty selection,如果返回empty selection,我们该如何将数据绑定给它,我们可以将数据绑定给后续即将出现的圆圈

例子:
how do i draw a circle for every row of my data?

d3.select('svg')                    #selects a container svg element on the page
  .selectAll('circle')              #creates a empty selection to bind data
  .data(data)                     #binds data to the empty selection 
  .enter()                            #select all bound data elements not displayed 
  .append('circle')             #create svg elements for the bound data 

26. 运用联接来思考

D3的强大之处在于数据绑定前的选择,数据绑定本身,以及绑定数据后的选择,比如上例中.enter()实际上是一种特殊类型的select,我们最终向这个enter()选择中的每个元素的页面添加形状(圆圈)、SVG或者HTML
Mike Bostock 的运用联接来思考

27 运用联接join来思考

联接join源自数据库语言SQL ,是一种将两个不同表格或spreadsheet关联起来的方法
联接join可以理解为以某种合理的方式将两个不同的表统一起来,要联接两个表,我们要考虑它们共同的列

28. D3 中的联接

一边是数据,一边是web页面的SVG元素或者HTML元素
执行联接时候,我们需要将数据文件中的每一行和web页面相应的元素对应起来


叙事结构_第4张图片
image.png

没有映射值的表格行/没有绑定相应数据的页面元素?

.enter()

D3-键-用于将数据映射至元素-本例是department ID

声明性语法:构建复杂的动画,让各帧之间体现出仅存在部分变化的数据或页面元素

要更详细地了解联接和选择,请参考以下文章。
三个小圆圈(作者:Mike Bostock)
运用联接来思考(作者:Mike Bostock)
数据绑定(作者:Scott Murray)

30. 使用维恩图思考

Index.html页面中的svg元素
交集:之前通过.data(data)联接,将数据文件中的数据行绑定并关联至这些元素,页面上当前存在的HTML元素
蓝色:页面中尚未出现的数据行 ///.append('circle')将为每一行向页面添加一个元素
紫色:通过之前对数据绑定的选择而出现在页面上的元素
.enter()/.exit() 更新数据值或者样式


叙事结构_第5张图片
image.png

31. .exit() 和 .enter()

.exit() 和 .enter() 这两个函数可以视为相反的函数。都在数据绑定之后调用

.enter() 会返回不在 index.html(页面上)的 data.tsv 的每行数据选择的所有元素。

.exit() 会返回 index.html(页面上)选择的未绑定到数据的所有元素。
HTML/SVG elements currently on the page which are not bound to row of data.csv
使用情景:

  • 初次绘制图表时,且拥有可供用户根据某个类别筛选的子选项时使用
  • 不同时间点的数据存在变化的动画中使用
  • 通常用于从页面中移除不应再显示的元素

32. 从 Dimple 到 D3

在D3中创建Dimple JS图表+扩展+添加更多上下文
1.运行http服务器
2.在basic_charts_title.html中使用原生D3代码来实现dimple.js代码的功能
注意:在D3中执行某些简单操作,例如创建图表对象或者添加Y轴,有时会比在Dimple JS中繁杂得多,但它具有很强的灵活性,以便我们更改图表外观以及进行定制

33. 数据绑定过程步骤

var myChart = new dimple.chart(svg,data)

上面的代码用于将数据绑定至我们想在其中绘制图表的svg

替换为相应的D3语句如下:

debugger;  #在D3代码前后都放置了调试语句
d3.select('svg')                  
  .selectAll('circle')              #返回空选
  .data(data)                               
  .enter()                            
  .append('circle');  
debugger;

添加标题的代码:

d3.select('body')
  .append('h2')
  .text('World Cup Attendance');

在JavaScript中刷新页面,让其捕捉debugger
在调用.data(data) 之前,页面上只有SVG以及数据文件world_cup.csv
我们使用D3的常规功能通过AJAX加载了这个数据文件,如果检查数据变量,就会发现它是一个JavaScript数组
在这个例子中,数组中有836个元素
我们可以以列表方式显示数据:

console.table(data);

在 Javascript 中,你可以使用 slice() 方法获取数组的子集。

slice() 文档

代码

data.slice(0, 10);

会返回数据数组中的前 10 个对象。记住索引从 0 开始。切片法不包括最后一个对象(在这个案例中,索引为 10 的对象)。

console.log(data.slice(0, 10));

上面的代码会在控制台用可排序表格打印出数据文件的前 10 行。

35.数据绑定过程中的返回

d3.select('svg')             #the svg element on the page not bound to data
  .selectAll('circle')              #返回空选 the empty selection 
  .data(data)                               #an array of placeholder elements to bind data 
  .enter()                            #an array of javascript objects with a _data_ field 
  .append('circle');  
d3.select('svg').selectAll('circle').data(data)     

D3将在这个调用中将数据文件中的数据行绑定至页面上的元素,但是页面没有任何圆圈,如何将数据绑定至空选。
上面的数据绑定返回了一个包含836个元素的数组,由于页面没有任何对应于数据行的元素,即页面上没有任何绑定至数据的元素,这时D3将创建空的占位符节点,可以将它理解为JavaScript控制台中的虚拟HTML节点,只是它们还没有作为SVG元素显示到页面中来,每个虚拟占位符都将关联至数据文件中的某个数据行,返回的数组实际上就是已关联某些数据的占位符元素数组,即数据绑定至占位符元素

现在我们已经有了绑定至虚拟占位符的数据,那我们要如何将数据绘制在页面上呢,这就需要借助.enter()来实现,.enter()对应的d3 selection包含了所有已绑定至某些数据但尚未出现在页面的虚拟节点,也就是占位符,在此例中,由于页面上目前没有任何内容,.enter()只是对应于已绑定至数据中的每一行的所有占位符
.enter()对应于实际的JavaScript对象,这些对象包含代表数据文件中的某一行的数据字段

跟随 Jonathan 的操作自行调试代码,逐条检查你的 D3 代码每行返回的内容。这可以帮助你更深入地理解 D3 代码的运作。
你应该检查 [Array[836] ] 的内容,看看你在调试代码时的第一个对象。

36.含绑定数据的圆圈

Mike Bostock 的选择的原理
Ritchie S. King 的运用 D3 进行视觉叙事
这本书讲述了如何在 D3 中使用动画和交互创建柱状图。其中的柱状图解释了“世界是否在变老”的问题。换句话说,这个问题谈及了青年或成人的年龄分布趋势。

d3.select('svg')             
  .selectAll('circle')  
  .data(data)                               
  .enter(); 

上述代码返回的对象里有__data__
__data__属性对应于一个对象

__data__:{attendance: "23000", team1: "Austria", team2: "Hungary", goals: "1-Feb", tie: "FALSE", …}

它包含数据文件中一行的所有字段
结合使用.enter() 和.append('circle'),就可以将数据文件中的数据和svg圆圈元素合并起来

37. 可视化世界杯的每场比赛

轴构建代码如下:

var x = myChart.addTimeAxis("x", "year"); 
myChart.addMeasureAxis("y", "attendance");
x.dateParseFormat="%Y"  #将一年的所有赛事汇总到一起,计算观赛人数
x.tickFormat="%Y";
x.timeInterval = 4
myChart.addSeries(null, dimple.plot.scatter);
myChart.addSeries(null, dimple.plot.line);
myChart.draw();

38.传达你的信息

对于数据,我们想要什么类型的叙事?如何达到这个目的?
要创建一个有效、有吸引力的图表,需要一个曲折的过程
探索性数据分析常常能够帮你找到需要传达的信息
在本例中,我们想要传达的信息是:
我们正处于一个全球化和资本化的时代,这是从这些年世界杯观赛人数不断增多可以得到的结论
全球化:早期世界杯不那么出名,那个时候的世界受到地理和后勤等方面的限制,而后来随着世界交通产业的发展,世界上各个国家的人们都可以去观看在一个国家举办的世界杯
资本化:随着赛事越来越受欢迎,FIFA和主办国都能从游客流入和旅游业获得收益
我们需要做的就是通过简单的图表传递以上信息
数据可视化图表的迭代过程帮助我们以高效的方式传达我们的信息
通过EDA得到我们要传达的信息后,我们就制作并改进可视化图表,将信息传达给观众

39. 在刻度中使用 extent()

如何能高效地传达随着时间产生的变化
静态图表显示的是随着时间的推移呈现出来的趋势,但是并没有明确显示数据中的一些细微差别
-- 解决方法:使用更精细的粒度显示我们的数据
某一年的所有观赛人数 -- 每一场比赛的观赛人数

更改创建轴的代码

var x = myChart.addTimeAxis("x", "year"); 
x.dateParseFormat="%Y"  #将一年的所有赛事汇总到一起,计算观赛人数
x.tickFormat="%Y";
x.timeInterval = 4
myChart.addMeasureAxis("y", "attendance");

将数据值转化为对应的像素点
在D3中绘制x轴和y轴:
1.找到我们想要显示的各列的区间
extent()函数能够从访问函数返回的信息中为一个已知数据确定最大值和最小值
x轴日期列:
y轴观赛人数:

var time_extent = d3.extent(data,function(d){
    return d['date'];
});
var count_extent = d3.extent(data,function(d){
    return d['attendance'];
})

d3.extent 文档

40. 创建时间和参赛人数刻度

将日期和观赛人数从初始数据映射到实际的像素点,我们需要scale()函数

var time_scale = d3.time.scale()
    .range([margin,width])
    .domain(time_extent);

var count_scale = d3.scale.linear()
    .range([height,margin])
    .domain(count_extent);

41. 在绘图函数前解析数据

d3.tsv('world_cup_geo.tsv',function(d){
},draw;

D3 时间格式化文档

参考以下图表,了解与画布相关的边界、高和宽以及将要绘制的数据。

43. D3 解析日期和时间

D3仅会根据我们期望的时间模式,进行模式匹配

format = d3.time.format("%d-%m-%Y(%H:%M h)");
d3.tsv('world_cup_geo.tsv',function(d){
    d['date'] = format.parse(d['date']);
    d['attendance'] = +d['attendance'];
},draw;

44.解析概述和解析观赛人数

format = d3.time.format("%d-%m-%Y(%H:%M h)");
d3.tsv('world_cup_geo.tsv',function(d){
    d['date'] = format.parse(d['date']);
    d['attendance'] = +d['attendance'];
},draw;

45.解析观赛人数

“使用 Mozilla 开发者网络 (MDN) 上的 JavaScript 文档找出我们在参赛人数列执行的操作的名称,以及这个操作的作用是什么。”

“使用 Mozilla 开发者网络 (MDN) 上的 JavaScript 文档,找出我们在参赛人数列执行的操作的名称,以及这个操作的作用是什么。”

提示:不是加法。

一元加法 (+) 运算符类型转换示例。

使用一元 (+) 运算符的原因在于将参赛人数字段的值从字符串类型(字符格式)转换为整数类型(数值格式)。

而一元否定运算符/负一元运算符 (-) 可以将代表整数的字符串转换为一个负整数。

“如果我们尝试在没有自然数字表示的字符串上使用一元正号或一元负号,我们就不会获得数字 (NaN)。”下方的示例突出了这种差别。

var num = "3";
+num;

returns 3

var num = "three";
+num;

returns NaN

请注意,当在包含字母数字字符的字符串上使用一元 (+) 运算符时,返回的值为 NaN

问题:
使用什么运算符转换'attendance'字段,这个运算符能够做什么?
答:一元运算符 + 是JavaScript将字符串转换成整数的一个运算符
'attendance'字段最初是什么数据类型?转换成了什么数据类型?
答:最初是字符串 转换成了整数

如果我们对不包含自然数字表示的字符串使用一元加法/减法运算符,我们就得不到数字结果

46. 使用函数检查数据

在JavaScript中,检查某个具体的数据类型是很困难的,我们不得不使用instanceof运算符,通过右侧内容对左侧内容进行布尔检查,在该例中,如果d['date']确实是一个JavaScript日期对象,会返回true,否则返回false

d['date'] instanceof Date 

我们可以用点标记/中括号标记来存取一个对象

d['attendance']
d.attendance 

47.创建轴

在D3中创建轴的一个难点是:
找出适合两个轴的尺度

var time_axis = d3.avg.axis()
    .scale(time_scale)
    .ticks(d3.time.years,2); 刻度线2年

var count_axis = d3.svg.axis()
    .scale(count_scale)
    .orient('left');

在 D3.js 中设置刻度、域和范围

48. 在页面上添加轴

只有当我们在HTML或SVG页面选择一些元素,并添加一些实际轴对象显示为SVG的视觉表示的东西后,它才属于JavaScript范围

“g”元素类似于 HTML div 标签,这是对不包含内视觉显示的其他SVG元素进行分组的一个办法,将svg中的'g'元素想象成一群其他svg对象周围的隐形围墙,

var time_axis = d3.avg.axis()
    .scale(time_scale)
    .ticks(d3.time.years,2); 刻度线2年

var count_axis = d3.svg.axis()
    .scale(count_scale)
    .orient('left');

d3.select('svg')
    .append('g')
    .attr('class','x axis')
    .attr('transform','translate(0,'+height+')') #移动包含在组内的所有内容
    .call(time_axis);

d3.select('svg')
    .append('g')
    .attr('class','y axis')
    .attr('transform','translate(0,'+margin+')') #移动包含在组内的所有内容
    .call(count_axis);

why set 'axis' as a class on each axis?
to style both the x axis and y axis using CSS

你可以从 Scott Murray 关于轴的短教程中详细了解 call() 函数。

高端 D3.js 也提供关于轴和 call() 函数的相似教程。

call() 函数的 d3 文档

49. 定位和绘制轴

D3 call() 方法可以让你将 D3 选择传递到一个函数,促进剩余库的函数链语法。在我们的案例中,它可以让我们将 g 选择传递到轴函数。

要详细了解轴的 call() 函数,请参阅高端 D3 上的“调用 D3.js Axis 函数”部分。

50. 匿名访问器函数

var time_extent = d3.extent(data,function(d){
    return d['date'];
});
var count_extent = d3.extent(data,function(d){
    return d['attendance'];
})

51. 圆圈在哪里?

我们创建函数时,每个svg都会增加到页面中
每个有绑定数据的元素都有一个_data_

d3.selectAll('circle');
d3.selectAll('circle')[0][0];
d3.selectAll('circle')[0][0].__data__;

52.D3 隐藏了复杂性

可通过更改.__data__attribute上的独立字段修改圆圈的数据

d3.selectAll('circle')[0][0].__data__['attendance']=1000000

53. 检查访问器函数

D3需要一个像素点,来确定圆圈的实际位置,在图标上确定具体日期和具体观赛人数的像素点
获取像素点的代码:

time_scale(d['date']);

54. 明智地使用变量

如果我要修改一个变量,比如让圆圈的半径变大或者圆圈的颜色,不必对各处代码都修改

55.每届世界杯比赛观赛人数

使用CSS解决样式问题
变更样式,来自“HTML 和 CSS 入门”课程。
D3 基本原理(向下滚动至 CSS 部分),作者:Scott Murray
更改圆圈的不透明度,可以在 html 文件顶部的样式标签之间使用以下 CSS 代码来做到这一点。

circle {
    opacity: 0.4;
    stroke: none;
}

不透明度指缺乏透明度或半透明度。在可视化中,我们想要降低圆圈的不透明度,而增加透明度。

56. 回顾和数据依赖

d3.selectAll('circle')
  .attr('cx',function(d){   #可将function看作是某类别的属性
      debugger;
      return time_scale(d['date']); 
  })                                  #对每个数据点或圆圈,根据日期修改x轴位置
  .attr('cy',function(d){
       return count_scale(d['attendance']);
  })                             #根据观赛人数修改y轴位置
  .attr('r',radius)
  .attr('fill',color);

在D3中使用匿名访问函数时,通常需要将它们视为数据相关的值,根据绑定数据,访问函数从这些数据中返回某些值,这样我们可以对每个数据点的每个函数进行自定义,这里的数据--根据数据--的日期确定x轴的位置等等

57. 使用 D3 代码设置主场比赛样式

“JavaScript 基础”课程中的 if 语句
慢慢向下滚动,寻找三个提示。

d3.selectAll('circle')
  .attr('cx',function(d){   #可将function看作是某类别的属性
      return time_scale(d['date']); 
  })                                  #对每个数据点或圆圈,根据日期修改x轴位置
  .attr('cy',function(d){
       return count_scale(d['attendance']);
  })                             #根据观赛人数修改y轴位置
  .attr('r',function(d){
      if (d['home']===d['team1']||d['home']===d['team2']){
          return radius * multipiler;        #增加表示主队的圆圈的半径
      } else{
          return radius;
      }
  })
  .attr('fill',function(d){
      if (d['home'] === d['team1']||d['home']===d['team2']){
          return 'red'          #以红圈表示本国
      } else {
          return 'blue';
      }
  });

58.并置和比较

在图表和数据中增加背景的常见技巧之一是:
并置或比较
例如:散点图中主队的圆圈变红色、半径变大,将人们的注意力集中在主队参加的比赛上,这样查看图表的人就能将这些比赛与主队未参加的比较进行比较
这是利用了潜意识加工的原理
再次提醒,我们要传递的信息是资本化和全球化

59.图形中的新数据故事

最后得到的图如下:


叙事结构_第6张图片
image.png

可以看到,世界杯比赛早期,主队参加的比赛观赛人数会很多,出现这种情况的原因可能是大部分球迷来自举办国,由于当时的交通和技术的限制,大家很难抵达世界杯比赛现场,随着时间的推移,不同的年份,主队有时甚至不参加淘汰赛,而有些更有看点的比赛的观赛人数甚至超过了主队参加的比赛,这是因为随着航空业的发展,航线不断增加,球队和球迷能更容易地到达世界各地

60.为读者提供的背景信息

探索性数据分析和可视化图表的区别:
除了图表以外,给主队比赛添加颜色本质上可能具有探索性,我们已经在D3上创建了一个精细的可视化图表,我们也发现,想要在数据中传达有趣的见解,也许我们使用了更加灵活的工具进行了探索性数据分析,比如ggplot2,matplotlib,R,python
将主场比赛的圆圈标红标大,我们是在传递信息,但是如果我们的读者不知道我们的数据有什么内容,不查看数据来源,也不会去查看D3代码去了解圆圈的颜色是根据主队是否参加比赛决定的,他们不知道红色代表什么,不知道它为什么重要,我们图表绘制人员知道我们要传达的是什么,但是仍然很难向一般观众解释

61.我是“传奇”

有一个办法可以解决读者不知道红圈代表什么的问题
在图标上增加简单的图例,图例可以有效地将图标和各个圆圈联系起来
要在可视化图表或图片中添加背景知识,一个简单有效的方法就是添加文本的标签或者注释,下面展示如何用文本添加图例

var legend = svg.append('g')  #在svg中添加组元素
  .attr('class','legend')  #为其指定图例类型
  .attr('transform','translate('+(width - 100) + "," + 20 +")") #将组移动到x轴上,比宽度小100的位置,在y轴上的位置是20,y轴上的0是图表的顶部,因此组的位置是顶部向下20个像素的位置
  .selectAll('g')
  .data(["Home Team","Others"])
  .enter().append("g");

由于我们的页面没有图例,enter()会返回两组元素占位符,一组针对主队,一组针对其他队,这些占位符和主队还有我们添加其他元素的其他队绑定

62. 在图例上添加圆圈

在图表上绘制一个与我们想要标示的圆具有相同大小和颜色的圆

legend.append("circle")
  .attr("cy", function(d,i) {  #i 得到数据点索引: i=0 home,i=1 others 
     return i*30;
            })
  .attr("r", function(d) {
      if (d=='Home Team') {
          return 5;
          } else {
                    return 3;
          }
   })
   .attr("fill", function(d) {
      if (d=='Home Team') {
          return 'red'
      } else {
          return 'blue';
      }
            });
   };

63.在图例上添加文本

 legend.append("text")
              .attr("y", function(d, i) {
                  return i * 30 + 5;
              })
              .attr("x", radius * 5)
              .text(function(d) {
                  return d;
              });

text SVG 元素的 y 属性定义了下列活动的基线,即在哪里绘制对应第一个字母(默认)左边缘的文本和 x 属性。或者更简单地说,xy 定义了开始画文本的左下角的位置。 再看一眼展示了所有世界杯赛出席率的世界杯出席率图。 你在图中注意到什么? 你是否认为你在这个话题方面的知识或任何偏见引导你从图中得出某个结论? 在讨论“世界杯解读 (World Cup Interpretations)”中分享你的看法。

在 课程中,Jonathan 提到默认的文本大小为 10px(并非在任何时候都是如此)。更灵活的文字置中方法是使用文本元素的 text-anchor 和 alignment-baseline 属性。

叙事结构_第7张图片
image.png

64. 所有世界杯比赛回顾

本例是一个作者驱动性非常强的叙事,原因:
静态;
作者决定让红色大圆圈代表主队,从而决定让读者关心什么信息,其他信息则没有那么引人注目了;
作者影响着读者对呈现出的图表的理解方式
我们要传递的信息是:世界全球化/收益资本化
应该随时注意:数据偏差/作者偏差/读者偏差
要随时考虑观众如何理解图表,考虑观众如何与可视化图表互动

65. 第三课回顾

本课程所有代码如下:



  
    
    
    
      

    
  

  


下一课:
运用互动和动画在特定的可视化图表中添加新的深景效果

你可能感兴趣的:(叙事结构)