news 2026/9/11 18:50:10

用 Vue.js 与 D3 构建“危险关系“书信网络可视化:Data-Science-For-Beginners 第 13 课实战项目运行与源码解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
用 Vue.js 与 D3 构建“危险关系“书信网络可视化:Data-Science-For-Beginners 第 13 课实战项目运行与源码解析

用 Vue.js 与 D3 构建"危险关系"书信网络可视化:Data-Science-For-Beginners 第 13 课实战项目运行与源码解析

【免费下载链接】Data-Science-For-Beginners10 Weeks, 20 Lessons, Data Science for All!项目地址: https://gitcode.com/GitHub_Trending/da/Data-Science-For-Beginners

本文围绕 Data-Science-For-Beginners 仓库中第 13 课「制作有意义的数据可视化」的配套实战项目(solution 完整版)展开,讲解如何在本机搭建、运行并理解一个基于 Vue.js 与 D3 的交互式网络图应用,其数据源是 1782 年法国书信体小说《危险关系》(Les Liaisons Dangereuses)的 175 封书信。读完本文,你将掌握npm工作流下的安装、开发、构建与代码检查命令,并能读懂Nodes.vue中从原始书信数据到力导向网络图的完整转换逻辑。

一、项目背景:用可视化回答"谁是主角"

在 第 13 课课程文档 中,作者系统讲解了数据可视化中的六类关键议题:选择合适的图表类型、避免误导性图表、合理使用颜色、提升可读性、动画与 3D 展示,以及构建创意可视化。课程的实战项目便是一个创意可视化的范例:把《危险关系》这部书信体小说中人物之间的通信关系绘制成一张可拖拽的社交网络图——每个节点代表一位写信人或收信人,每条连线代表一次书信往来,运行后可以直观地"看出"谁是叙事网络中真正的枢纽人物(如 Vicomte de Valmont 与 Marquise de Merteuil)。

项目使用vue-d3-network库(基于 Vue.js 与 D3 封装的网络图组件)实现。本仓库同时提供 starter 版(留有待补全的createLinks()方法,供学习者动手)和 solution 版(完整可运行实现),本文以 solution 版为分析对象。

二、环境要求:Node.js 与 NPM

项目通过 solution/package.json 声明运行环境,其中engines字段明确要求:

"engines": { "node": ">=20.0.0" }

即机器上需要安装Node.js 20.0.0 或更高版本(NPM 随 Node.js 一同安装)。这一点在原文档中已明确说明,是本项目可运行的前提条件,建议先执行node --versionnpm --version确认环境满足要求。

从 package.json 的依赖清单可以进一步了解技术栈:

  • 运行时依赖(dependencies)vue(^3.5.19)、vue-d3-network(0.1.28)、core-js(^3.6.5);
  • 开发依赖(devDependencies)@vue/cli-plugin-babel@vue/cli-plugin-eslint@vue/cli-service(均为 ~5.0.8),以及babel-eslinteslinteslint-plugin-vuevue-template-compiler
  • 安全补丁(overrides)qs固定为 6.14.2、braces>= 3.0.3、serialize-javascript固定为 7.0.5,用于规避依赖链中的已知漏洞;
  • browserslist> 1%, last 2 versions, not dead,决定 Babel 与 Autoprefixer 的转译目标浏览器范围。

这里有一点值得注意:package.json 声明的是 Vue 3(^3.5.19),而 src/main.js 中的挂载写法(Vue.config.productionTip = falsenew Vue({ render: h => h(App) }).$mount("#app"))是 Vue 2 经典风格,同时 devDependencies 中保留了vue-template-compiler(Vue 2 配套)。从这套依赖组合可以推断,该项目是在 Vue 2 时代搭建、后续版本号被升级到 Vue 3 的遗留工程,运行时以仓库现状为准,不必在本文范围内深究。

三、项目结构:solution 目录逐文件解读

solution 版采用 Vue CLI 的标准目录布局:

solution/ ├── public/ │ ├── favicon.ico # 站点图标 │ └── index.html # HTML 入口模板 ├── src/ │ ├── assets/ │ │ └── letters.json # 175 封书信的结构化数据 │ ├── components/ │ │ └── Nodes.vue # 核心网络图组件 │ ├── App.vue # 根组件 │ └── main.js # Vue 实例入口 ├── babel.config.js # Babel 转译配置 └── package.json # 依赖与脚本定义
  • App.vue 只做一件事:导入并在根节点渲染Nodes组件,是典型的"薄壳"根组件;
  • main.js 创建 Vue 实例并挂载到#app节点;
  • babel.config.js 使用@vue/cli-plugin-babel/preset预设,负责把现代 JavaScript 转译为兼容目标浏览器的代码;
  • 数据的核心在 src/assets/letters.json,可视化逻辑的核心在 src/components/Nodes.vue。

四、数据层:letters.json 的书信结构

letters.json记录了《危险关系》全书的 175 封信,每条记录是一个 JSON 对象,字段结构如下(节选自 letters.json):

{ "letter_num": 1, "from": "Cécile de Volanges", "to": "Sophie Carnay", "date": "8/3/17**", "location": "Ursulines" }

各字段含义:

字段说明
letter_num信件的序号(1~175,其中第 40 封后还有一个"40-suite"续条)
from写信人姓名
to收信人姓名
date写信日期,书中为隐去年份,写作17**的形式
location写信地点(部分条目缺失,部分为"…"占位)
notes可选备注,例如 "4h am"(凌晨四点)、"duel challenge"(决斗挑战)、"death of Valmont"(瓦尔蒙之死)等情节节点

这套"发件人—收件人"的二元关系,正是构建网络图的原料:人物是节点(node),信件是连线(link)。

五、核心实现:Nodes.vue 的建图逻辑

Nodes.vue 是项目的灵魂。模板中通过vue-d3-network提供的d3-network组件渲染网络图:

<d3-network :net-nodes="nodes" :net-links="links" :options="options" />

传入三个数据属性:节点数组nodes、连线数组links、渲染选项options。组件内部用 D3 的力导向布局(force-directed layout)自动排布节点。

5.1 节点与连线的构建

组件在created()生命周期钩子中完成数据装配,分为三步:

第一步:定义角色名单。characters数组列出了叙事中出现的 15 个写信/收信主体,例如"Chevalier Danceny""Marquise de Merteuil""Cécile Volanges""Vicomte de Valmont",以及"Anonyme"(匿名者)、"…"等特殊占位角色。

第二步:调用createLinks(characters)建立连线。这是课程要求学习者自行补全的关键方法,solution 中的完整实现是一个双重循环:

createLinks(characters) { //loop through letters let f = 0; let t = 0; for (var i = 0; i < letters.length; i++) { for (var j = 0; j < characters.length; j++) { if (characters[j] == letters[i].from) { f = j; } if (characters[j] == letters[i].to) { t = j; } } this.links.push({ sid: f, tid: t }); } }

其工作原理是:外层遍历letters.json的每一封信,内层在characters名单中查找发件人与收件人的下标,再把{ sid: 发件人下标, tid: 收件人下标 }追加进links数组。vue-d3-network正是依据sid(source id)与tid(target id)在节点之间绘制连线,因此把人物姓名转换为数字下标是让库能消费数据的关键一步。

第三步:生成节点数组。对每个角色创建一个节点对象:

this.nodes.push({ id: j, name: characters[j], _size: this.getCount(characters[j]) + 20, _color: "#" + Math.floor(Math.random() * 16777215).toString(16), });
  • id为角色在名单中的下标;
  • _sizegetCount(name)计算——该方法统计该角色作为收信人出现的次数(入度),再加 20 作为节点半径基数,收信越多节点越大;
  • _color为随机生成的十六进制颜色(Math.random()取 0~0xFFFFFF 再转 16 进制),所以每次刷新配色都可能不同。

5.2 渲染选项

options计算属性向d3-network传递布局与展示参数:

options() { return { force: 3000, // 力导向布局的斥力强度 size: { w: 600, h: 600 }, // 画布尺寸(宽高均为 600px) offset: { x: 0, y: 0 }, // 画布偏移 nodeLabels: true, // 显示节点标签(角色名) linkLabels: true, // 显示连线标签 canvas: this.canvas, // 是否使用 Canvas 渲染(data 中默认为 false,即 SVG 渲染) }; }

其中force: 3000决定节点间的相互斥力,数值越大节点越分散;linkLabels: true会让每条连线上都显示标签。样式部分(Nodes.vue 的<style>块)还定义了选中、固定(pinned)、悬停高亮等交互状态的视觉效果:普通节点为浅青绿色(#dcfaf3),选中节点描边为金色(#caa455),悬停时连线与节点描边变为琥珀色(rgba(250, 197, 65, 0.6))。

5.3 运行效果

项目运行后,页面中央即呈现这张可交互的书信社交网络图,读者可以拖拽节点重新布局,从节点大小与连线密度快速判断人物关系的主次:

六、完整运行步骤(继承原文档全部命令)

原文档给出了四条核心命令,以下逐一说明其作用与输出结果。

6.1 安装依赖

npm install

在 solution 目录下执行。该命令会读取 package.json 与仓库自带的package-lock.json,安装vuevue-d3-network等全部依赖并写入node_modules目录。首次安装耗时取决于网络状况。

6.2 开发模式:编译并热重载

npm run serve

对应 package.json 中的"serve": "vue-cli-service serve"。它会启动一个本地开发服务器,编译项目并监听文件变化,修改代码后页面自动热重载,无需手动刷新。终端会打印出本地访问地址(通常为http://localhost:8080)。这是日常开发调试推荐使用的命令。

6.3 生产构建:编译并压缩

npm run build

对应"build": "vue-cli-service build"。它会对代码进行编译与压缩(minify),输出静态资源到dist/目录,用于部署上线。与开发模式相比,生产构建会启用代码压缩、去除开发期提示,产物体积更小、加载更快。

6.4 代码检查:Lint 并自动修复

npm run lint

对应"lint": "vue-cli-service lint"。它基于 ESLint(配置见 package.json 的eslintConfig字段:plugin:vue/essentialeslint:recommended)检查源码中的语法与风格问题,能自动修复的会直接修复,不能自动修复的会列出提示。建议提交代码前运行一次。

七、定制与进阶:从 solution 走向自己的可视化

原文档最后提示:如需自定义配置,可参考 Vue CLI 的配置参考文档。在仓库范围内,你可以通过以下几种方式进一步定制本项目:

  1. 调整布局参数:修改 Nodes.vue 中options里的force(斥力强度)与size(画布尺寸),例如把size改为{ w: 800, h: 600 }以获得更宽的画布;
  2. 切换渲染后端:把data()中的canvas: false改为true,让d3-network改用 Canvas 渲染,适合节点数量庞大的网络图;
  3. 更换数据源:保持{ from, to, ... }结构的前提下替换letters.json的内容,即可把同一套网络图应用到任何"谁联系谁"型的数据(如邮件往来、合著论文、社交关系);
  4. 从 starter 开始练习:对照 starter 与 solution 的差异,自行补全createLinks()方法,是复现本课学习目标的推荐路径;
  5. 结合课程作业:完成第 13 课的 assignment,把课程中"选择正确图表类型""避免误导性图表""注重可读性与配色"等原则应用到自己的数据上。

八、结语

《危险关系》项目以不到百行的核心代码,演示了从结构化 JSON 数据到交互式力导向网络图的完整链路:letters.json提供关系数据,createLinks()把姓名映射为节点下标,getCount()用入度决定节点大小,d3-network组件负责布局渲染与交互。通过npm installnpm run servenpm run buildnpm run lint这一套标准工作流,你可以快速把它跑起来,也可以以此为模板,把任何关系型数据变成"一眼看清主角"的可视化作品。

【免费下载链接】Data-Science-For-Beginners10 Weeks, 20 Lessons, Data Science for All!项目地址: https://gitcode.com/GitHub_Trending/da/Data-Science-For-Beginners

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/11 18:47:22

从零部署到团队跑通:OpenProject 项目管理实操上手指南

从零部署到团队跑通&#xff1a;OpenProject 项目管理实操上手指南 【免费下载链接】openproject OpenProject is the leading open source project management software for product, project and portfolio management. A powerful Jira alternative with agile planning, is…

作者头像 李华