南宋末年,小白为救许仙,水漫金山,终被法海压在雷峰塔下。小青心生救姐, 执念死死纠缠法海,由此被法海痛下杀手,但因其执念落入修罗城幻境经历考验。几次危机 中小青被神秘蒙面少年所救,小青带着去救出小白、打倒法海、掀翻雷峰塔的执念历经劫难 与成长。强大的执念支撑着她必须要在弱肉强食的修罗城中活下去,带着一世的记忆走出修 罗城... ...一幕幕是否很熟悉呢?没错,这就是被誉为国产动画作品顶峰的电影《白蛇 2:青 蛇劫起》的剧情梗概。正所谓“一千个读者有一千个哈姆雷特”,对于这部电影,大家也是 众说纷纭,现在需要我们把大家的意见综合起来,进行可视化分析。
准备工作
准备一份数据集,这里我们采用CSV文件。CSV文件相比js常用的json和xml格式相比有不少优点。
- 简单易用:CSV 格式是一种非常简单、易于使用和理解的文件格式,适合各种编程语言和工具进行读写和处理。它没有复杂的数据结构或格式限制,可以轻松地在不同的应用和系统之间传输和共享数据。
- 轻量级高效:CSV 格式文件通常比类似 Excel 或 SQL 数据库等其他格式文件更小、更轻量级,因此在网络传输和存储方面更加高效。同时,由于没有复杂的数据结构,CSV 格式的数据处理速度也非常快。
- 可读性强:由于 CSV 格式是文本格式,因此非常容易阅读和理解。相比于二进制格式文件,CSV 格式文件更容易进行数据分析和处理。
- 可移植性强:CSV 格式是一种基于文本的格式,因此可以轻松地在不同的操作系统和软件之间传输和共享数据。无论是 Windows、Mac 还是 Linux 系统,都可以使用 CSV 格式文件进行数据处理和传输。
- 可自定义性强:虽然 CSV 格式的数据结构很简单,但是可以通过自定义文件分隔符、文本编码、行结束符等参数进行更加灵活和定制化的设置。这使得 CSV 格式可以适应不同的数据处理需求和环境。
下面是准备好的CSV文件的部分内容:
id,用户名,城市,评分,评论,评论时间
1142669584,淇桐糯米饭啦,来宾,5,剧情非常有吸引力,看个动画片给了我惊喜,2021-08-31 23:56:30
1142662178,LnV14610189,西宁,5,画面感超强!,2021-08-31 23:36:00
1142666877,Alo861902585,广州,5,和一衔接的很不错,精彩,2021-08-31 23:34:41
加载CSV文件
在 D3.js 中,可以使用 d3.csv()
函数加载 CSV 文件。该函数返回一个 Promise 对象,可以使用 then()
方法或 await
关键字处理异步加载的数据。以下是一个示例代码:
d3.csv("data.csv").then(function(data) {
console.log(data);
});
在上面的代码中,我们使用 d3.csv()
函数加载名为 "data.csv" 的 CSV 文件,并在加载成功后将数据打印到控制台中。
解析 CSV 数据
使用 d3.csv()
函数加载 CSV 文件后,D3.js 会自动将文件内容解析成 JavaScript 对象数组。每个对象对应一行数据,每个属性对应一列数据。例如,如果我们加载了上面提到的 CSV 文件,D3.js 将返回以下数组:
[
{
"id": "1142669584",
"用户名": "淇桐糯米饭啦",
"城市": "来宾",
"评分": "5",
"评论": "剧情非常有吸引力,看个动画片给了我惊喜",
"评论时间": "2021-08-31 23:56:30"
}
]
在解析 CSV 数据后,我们可以对其进行操作和处理。看的出来数据集很大,有20584条数据。
数据可视化
可视化要求:
- 从 1.5 分开始,每 0.5 分设置一个等级,分别统计每个评分等级下的人数,绘制柱状。
- 要求柱状图添加比例尺、坐标轴和渐变颜色标尺。
- 将每个等级的人数与总人数的占比计算出来,绘制饼图。并添加标注即可。
const div = d3.select('#svg-container');
let svg = div
.append('svg')
.attr('width', 1000)
.attr('height', 500)
// 定义一个对象,key是评分,value是对应的等级
const levelMap = {
'5': 7,
'4.5': 6,
'4': 5,
'3.5': 4,
'3': 3,
'2.5': 2,
'2': 1,
'1.5': 0
};
// 定义一个数组,用来存储每个等级的人数
let level = [
{ name: '1.5', count: 0, dy: -30 },
{ name: '2.0', count: 0, dy: 0 },
{ name: '2.5', count: 0, dy: 30 },
{ name: '3.0', count: 0, dy: 60 },
{ name: '3.5', count: 0, dy: 80 },
{ name: '4.0', count: 0, dy: 75 },
{ name: '4.5', count: 0, dy: 0 },
{ name: '5.0', count: 0, dy: 0 }
];
// 遍历数据,将每个等级的人数加1
data.forEach(d => {
let score = d.评分;
let levelIndex = levelMap[score];
level[levelIndex] && level[levelIndex].count++;
});
// 定义一个div,用来显示提示信息
const tips = div.append("div")
.style("position", "absolute")
.style("border-radius", "5px")
.style("padding", "10px")
.style("opacity", 0)
.style("font-size", "12px")
.style("color", "#fff")
.style("background", "rgba(0,0,0,0.6)")
.style("pointer-events", "none")
.style("border", "1px solid #666")
- 使用d3.csv()方法读取数据文件data.csv,并在读取成功后调用回调函数。
- 在回调函数中,首先使用console.log()方法打印读取到的数据data,以便查看数据。
- 接着定义一个对象levelMap,用来将每个评分映射为对应的等级。例如,5分评分对应等级7,4.5分评分对应等级6,以此类推。
- 定义一个数组level,用来存储每个等级的人数,并为每个等级添加对应的名称、人数和dy属性。
- 遍历数据,对于每个数据项,根据其评分获取对应的等级索引,然后将该等级的人数加1。
- 定义一个div元素tips,用来显示鼠标悬停提示信息,并设置其样式。
绘制柱状图
-
使用level.reverse()方法将等级数组level翻转,以便按从高到低的顺序显示等级。
-
定义画布的宽度、高度和内边距。
-
使用svg.append('defs')方法定义一个线性渐变,用来填充矩形的颜色。
-
使用svg.append('text')方法添加标题、坐标轴标签和单位标签。
-
使用d3.max()方法获取等级数组中人数最多的等级,并使用d3.scaleLinear()和d3.scaleBand()方法定义x轴和y轴的比例尺。
-
使用d3.axisBottom()和d3.axisLeft()方法定义x轴和y轴的刻度,并使用svg.append('g')方法添加坐标轴。
-
使用svg.append('g')方法添加矩形和文本元素,并使用d3.event对象和鼠标事件监听器实现鼠标悬停提示功能。
绘制饼图
-
定义变量和数据:首先,代码定义了一些变量,如宽度、高度、半径等,并创建了一个包含数据的数组。
-
创建饼状图数据和形状:接下来,代码使用d3.pie()函数根据数据创建了饼状图的数据,然后使用d3.arc()函数创建了饼状图的形状。
-
设置颜色比例尺:代码定义了一个颜色比例尺,用于根据数据的名称设置每个部分的颜色。
-
绘制饼状图:在绘制饼状图的过程中,代码使用了mousemove和mouseout事件监听器,当鼠标在饼状图上移动时,会更新提示框的内容和位置;当鼠标离开饼状图时,提示框会被隐藏。同时,还使用了polyline和text元素绘制了饼状图的边框和标签。
-
创建图例:最后,代码创建了一个图例(legend),用于显示每个部分的名称。图例中的矩形和文本元素分别表示饼状图的各个部分和它们的名称。
参考文章
关于图的绘制和交互效果文章不再描述,可以参考我之前发布的文章。
建议
多翻翻我的《D3.js可视化实战》专栏的文章,点赞 关注 收藏。