私人设计网站推荐,天眼官方网站,自己做网站需要什么软件,手机视频制作软件D3#xff1a;Data-Driven Documents • 通过D3提供的接口来基于数据操控文档的各个图元。
标题对于D3(本讲解)最为重要的标签#xff0c;主要操作的对象(画布)
HTML - 导入D3.js D3.js作为JavaScript的外库#xff0c;必须先将其导入#xff0c;如#xff1a; Python的…D3Data-Driven Documents • 通过D3提供的接口来基于数据操控文档的各个图元。
标题对于D3(本讲解)最为重要的标签主要操作的对象(画布)
HTML - 导入D3.js D3.js作为JavaScript的外库必须先将其导入如 Python的importC/C的include、 Java的import、node.js的require… … … 通过Script标签导入 直接通过互联网链接 https://d3js.org/d3.v5.min.js通过本地服务器链接推荐 ./d3.min.js通过unpkg链接 https://unpkg.com/browse/d35.15.0/dist/d3.js 尽可能使用本地的d3.min.js库。
svg-可缩放矢量模型
svg d3用来绘制的画布可缩放矢量图形英语scalable vector graphicssvgsvg是d3.js主要操作的对象 const svgde3.select(‘svg’)d3.js获取svg对象 svg同时也是一个容器用于包含画在上面的各个图元svg作为矢量图不会随着图片的缩放而发生失真 引入svg svg height200 width200 styledisplay:block;margin:0 autog transfromtranslate(0,60)rect width100 height100 fill#eee /circle r15 fill#72bf67 cx25 cy30/circlecircle r15 fillRGB(100,149,237) cx75 cy30/circleg transformtranslate(15,60) rotate(10)path dM0,0 A40,40 10 0,0 65,0 fillnone strokegray stroke-width5/path/g/g/svgHTML–文档对象模型
HTML - DOMDOM - Document Object Model对于根节点的操作会影响到子节点最常用的父节点 中的 Axis可封装成一个groupLegend图例可封装成一个group https://en.wikipedia.org/wiki/File:DOM-model.svg JavaScript – D3中的常用接口
模板字符串 let a 10;let myString abc-${a}; (myString最终为’abc-10’) 数组 a [1, 2, 3]对象 a {name: ‘Shao-Kui’, age: 24.3, lab: ‘cscg’} D3数据可视化中常见对象数组如 a [{name: ‘Shao-Kui’, age: 25.3, dept: ‘cs’},{name: ‘Wen-Yang’, age: 23, dept: ‘cs’},{name: ‘Yuan’, age: 29, dept: ‘cs’}] 数组的排序 a.sort() 可加入回调函数来替代缺省的排序方案如对日期排序a.sort(function(a,b){ return new Date(b.date) - new Date(a.date); } 数组的查询 a.find( d d.name ‘Wen-Yang’)把字符串转换成数值(‘3.14’)D3.js经常读取CSV、JSON等文件会涉及大量的数组、对象的操作 D3语法基础概览
使用D3获取、修改、增加与删除节点图元数据的读取 – CSVD3.js的数值计算。比例尺 线性比例尺Linear Scale“条带”比例尺Band Scale 坐标轴的绘制 Margin。 Data-Join基础基于D3的基础语法与Data-Join绘制柱状图 元素标签的标识
当我们在一个同学群体中比如微信群对某些同学发出通知时 请学号为2020123456的同学在东主楼集合请计算机系研一的同学在东主楼集合 在一个群体中索引个体 通过唯一的标识索引到唯一的个体通过共同点索引到一批个体 元素标签的标识
操作元素首先需要知道元素的标识 即要得到已有或已经创建的元素 元素的ID 可以唯一找到元素的标识符 元素的Class 人为赋予的“类别”可以标记元素的集合其中的元素标签可以不相同 元素的标签 HTML自带的标签名称可以找到一批同类别的物体如所有的“矩形”使用自带的标签往往难以直接索引到目标元素 , , 等 使用D3查询SVG
d3.select(…) d3.select(‘#rect1’)查询ID为’rect1’的元素#表示后面的字符串是一个ID只找一个若有重名也只返回第一个 d3.selectAll(…) d3.selectAll(‘.class1’)查询所有class是’class1’的元素d3.selectAll(‘rect’)查询所有标签是’rect’的元素rect为SVG中的矩形标签有多少返回多少可配合Data-Join选取‘不存在’的图元 ID前加‘#’Class前加‘.’ 标签名前不加符号。基于层级的查询 d3.select(‘#maingroup rect’)d3.selectAll(.tick text’)d3.selectAll(‘#secondgroup rect’) 如’#secondgroup rect’ 首先会找到id为secondgroup的标签进一步找到secondgroup的子标签中是rect的仍然是对rect做查询只是结果通过父标签做了筛选 d3.select(…)也可用于查询类别如 d3.select(‘.class1’)但只会返回找到的第一个元素 因此对于class、标签名称的查询建议使用d3.selectAll对于特定某一个元素的查询建议使用d3.select 使用D3设置SVG中的属性
常见的属性 id, class特殊的属性可以使用.attr设置x, y, cx, cyfill, strokeheight, width, r (圆的半径)transform - translate, rotate, scale SVG的属性非常多且属性的取值 **范围类型 **各不同 tip1: 尽可能记住一些常见的属性以提高编程速度tip2: 遇到不认识or想要设置某个属性一定要查阅
https://developer.mozilla.org/zh-CN/docs/Web/SVG/Attribute
屏幕空间的坐标系与常见坐标系不同 左上方为原点Y、X分别垂直向下、水平向右 element.attr(…)
设置元素的属性: element.attr(‘attr_name’, ‘attr_value’) 两个参数属性名、设置的值rect1.attr(‘y’, ‘100’)d3.select(‘#rect1’).attr(‘y’, ‘100’) 获取元素的属性: element.attr(‘attr_name’) 一个参数属性名 链式调用 selection.attr(…).attr(…).attr(…).attr(…)返回的是选择的图元本身 修改整组属性
DOM 父节点的属性会影响子节点子节点的属性会相对于父节点 下方代码可以直接移动组内所有元素 d3.select(#maingroup’).attr(‘transform’, ‘translate(200, 100)’) 使用D3 添加**删除 **SVG元素
element.append(…) const myRect svg.append(‘rect’);const myRect d3.select(‘#mainsvg’).append(‘rect’)const myRect d3.select(‘#mainsvg’).append(‘rect’).attr(‘x’, ‘100’) D3的链式添加调用 const myRect d3.select(‘#mainsvg’).append(‘g’).attr(‘id’, ‘maingroup’).append(‘rect’).attr(‘fill’, ‘yellow’) element.remove() 会移除整个标签 Tip:在debug的过程中可以考虑使用’opacity’属性hack出移除的效果 element.attr(‘opacity’, ‘0’) 操控SVG 数据的读取 – CSV数据
第一行为属性列表后续每行对应一‘条’数据。CSV本质上是纯文本区别于EXCEL的格式。 d3.csv(…) 读取目标路径下的某一个CSV文件。例d3.csv(‘static/data/hello.csv’); d3.csv是一个JavaScript异步函数 不可以直接获得它的返回值如let myData d3.csv(‘static/data/hello.csv’); ❌ d3.csv(‘path/to/data.csv’).then( data { // ‘数据读取后的代码逻辑’ } ) 要通过.then( **data ** {…} )的方式来获得读取后的数据。then(…)中的 ‘data {…}’ 是一个函数。此函数接受的输入(参数)即data为读取后的数据。 JavaScript异步机制 d3.csv作为异步函数即便没有读取好数据后面的代码也会继续执行d3.csv被调用后其返回值是一个JavaScript的‘Promise’对象(object)Promise‘询问’数据读取好了之后要做什么‘做什么’即对应.then()中函数的内容。 代码调用示例 读取后的数据格式(接口)与原本的CSV结构不同。 D3.js的数值计算
数据可视化常涉及对数据的处理与计算 下述三个接口分别用于计算数组的最大值、最小值、[最小值最大值]。 d3.max(array) 返回数组中的最大值。d3.max([5,4,6,1,8,16,9]) // 16 d3.min(array) 返回数组中的最小值。d3.min([5,4,6,1,8,16,9]) // 1 d3.extent(array) 同时返回最小值与最大值以数组的形式即[最小值最大值]。d3.extent([5,4,6,1,8,16,9]) // [1, 16] 数组中的内容可以是任意对象 每个对象可能包含多个属性。具体取哪个属性的最大值通过回调函数来提示d3.max、d3.min与d3.extent。 例 let a [ {name: ‘Shao-Kui’, age:25, height: 176}, {name:‘Wen-Yang’, age:24, height: 180}, {name:‘Liang Yuan’, age: 29, height: 172}, {name:‘Wei-Yu’, age:23, height: 173}]d3.max(a, d d.age) // 29d3.max(a, d d.height) // 180d3.extent(a, d d.height) // [172, 180]d3.min(a, d d.age) // 23 比例尺
比例尺用于把实际数据空间映射到屏幕(画布)空间即两个空间的转化。常用于映射数据and创建坐标轴。区别主要在于数据的尺度不同 Scale - Linear
d3.scaleLinear() 定义一个线性比例尺返回的是一个函数。let scale d3.scaleLinear(); // scale为函数 scale.domain([min_d, max_d]).range([min, max]) 设置比例尺的定义域与值域。线性比例尺的定义域和值域都是连续的(Continuous)需分别给出最大值与最小值。const scale d3.scaleLinear().domain([20, 80]).range([0, 120]); 比例尺本质上是一个函数 scale(20) // 0scale(50) // 60 常结合读取的数据与d3.max等接口连用 const xScale d3.scaleLinear() .domain([0, d3.max(data, d d.value)]).range([0, innerWidth]); Scale - Band
d3.scaleBand() 定义一个‘条带’比例尺返回的是一个函数。let scale d3.scaleBand(); scale.domain(array).range([min, max]) 设置比例尺的定义域与值域Band比例尺的定义域是离散的(Discrete)值域是连续的。const scale d3.scaleBand().domain([‘a’, ‘b’, ‘c’]).range([0, 120]); 比例尺本质上是一个函数 scale(‘b’) // 40scale(‘c’) // 80 常结合JavaScript的array.map接口一起使用 let a [{name: ‘Shao-Kui’, value:6}, {name:‘Wen-Yang’, value:6}, {name:‘Yuan Liang’, value:16}]a.map(d d.name) // [‘Shao-Kui’, ‘Wen-Yang’, ‘Yuan Liang’]const yScale d3.scaleBand().domain(data.map(d d.name)).range([0, innerHeight])scale.padding(0.1) 设置条带的间距占各自区域的比重。 scale.bandwidth(): 返回条带的长度。 引入坐标轴
一个坐标轴为一个group 通常需要两个坐标轴。 坐标轴中包含 一个 用于横跨坐标轴的覆盖范围 若干个刻度(.tick) 每个刻度也是一个group 每个刻度下属还会包含一个 和一个 用于展示坐标轴的轴线如左到右或上到下 用于展示坐标轴的刻度值如实数、姓名、日期 可选一个标签用以描述坐标轴 坐标轴的定义通常需要比例尺。 定义坐标轴获得结果仍是函数 const yAxis d3.axisLeft(yScale);const xAxis d3.axisBottom(xScale);axisLeft左侧坐标轴。axisBottom底侧坐标轴。坐标轴的刻度对应比例尺的定义域。坐标轴在画布的绘制对应比例尺的值域。仅是对坐标轴的定义还未绘制。 绘制坐标轴 const yAxisGroup g.append(‘g’).call(yAxis);const xAxisGroup g.append(‘g’).call(xAxis);实际配置后会发现 中增添了与坐标轴相关的元素 任何坐标轴在初始化之后会默认放置在坐标原点需要进一步的平移。 关于 selection.call(…) 函数的输入为另一个函数。 另一个函数以selection本身(即图元)作为输入 另一个函数中会根据函数体的内容修改selection对应的图元。 定义一个空白的 D3会帮助我们定义好 另一个函数我们通过.call(…)让 得以在 另一个函数中修改。 const yAxis d3.axisLeft(yScale);const yAxisGroup g.append(‘g’).call(yAxis); 配置坐标轴
可以对坐标轴的风格进行修改 坐标轴本质上是图元的集合。d3.selectAll(‘.tick text’).attr(‘font-size’, ‘2em’);.tick是D3对于坐标轴定义的统一class 坐标轴的标签加入不在D3-Axis接口的负责范围内 通过对坐标轴的 标签 .append(‘text’)来实现 左纵轴坐标需要 .attr(‘transform’, ‘rotate(-90)’) 来旋转纵轴坐标旋转后x / y 会颠倒甚至取值范围相反回忆DOM父节点的属性会影响子节点而坐标轴默认的’fill’属性是 ‘none’因此请一定手动设置文字颜色 .attr(‘fill’, ‘black’) 引入坐标轴 - Margin
SVG对于D3.js是一个“画布”。SVG范围外的任何内容属于画布之外浏览器将不予显示。 然而坐标轴通常初始化在所在父节点的左上角。 定义Margin: const margin {top: 60, right: 30, bottom: 60, left: 200} 计算实际操作的 inner 长/宽 const innerWidth width - margin.left - margin.right;const innerHeight height - margin.top - margin.bottom; 在SVG下额外定义一个组作为新的根节点 const g svg.append(‘g’).attr(‘id’, ‘maingroup’).attr(‘transform’, translate(${margin.left}, ${margin.top})); Tip: HTML确实在样式表中提供margin属性然而设置其他图元的位置,仍需要计算innerWidth(Height)。 引入坐标轴
调用示例 比例尺可通过坐标轴可视化。 Data-Join 本质上是将数据与图元进行绑定 每个国家的人数绑定到矩形的长度疫情感染的人数比例绑定到圆的半径产品的销量绑定到矩形的长度各类别商品的销售占比绑定到扇形的弧度。 Why 以数据为中心(Data-Driven)的可视化操作 根据数据自动调整图元的属性。.attr(…)接口可基于图元自己绑定的数据自动调整属性值。 数据发生变化时可以自动对图元增删改查 不再需要手动添加、‘修改’、删除图元。根据数据的增加or删除or更新自动补充or移除or更新图元。 Data-Join并不是必要的操作不使用Data-Join同样可以画出所有可视化作品。 Data-Join只是让D3.js编程变得更高效且语法更简洁。 d3.selectAll(‘.class’)**.data( dataArray ) ** dataArray在保证是一个数组的前提下可以是任何形式 例 [0, 2, 32, 18];例[{name: ‘Sebastian’, value:384}, {name:’ Ciel’, value:32}, {name:‘Wen-Yang’, value:16}, {name:‘Shao-Kui’, value:19}]; .data(…)只考虑数据和图元数目相同的情况 dataArray是一个数组其中的每‘条’数据会与一个图元绑定。 默认的绑定按照双方的索引顺序 Data的Key后续D3中会讨论。 不调用.data(…)则图元不会与任何数据绑定 数据的更新只需要重新绑定另一个 dataArray 即可。 调用形式 **d3.selectAll(‘.class’).data(myData).join(‘图元’).attr(d …).attr((d, i) …) **.join(…)会根据数据的条目补全or删除图元。 若有新增的数据则会自动增加对应图元。若有修改的数据则会自动更新对应图元。若有删除的数据则会自动移除对应图元。 Data-Join – 用函数设置图元属性
selection.attr(‘attrbuteName’, ‘value’) 通过值设置属性 selection.attr(‘attrbuteName’, (d, i) {…}) 通过函数设置属性函数的输入为绑定的数据返回值为图元得到的属性值d为Data-Join中‘.data(array)’绑定给每个图元的数据。i为Data-Join中‘.data(array)’绑定图元的顺序即图元对应原本数组的第几个例d3.selectAll(‘rect’).attr(‘width’, (d, i) 1000 * d.age )例d3.selectAll(‘circle’).attr(‘cy’, (d, i) 200 * i 30);由于绑定数据的不同故得到的结果也不同。 设置图元属性的函数遵循如下规则顺序性 函数可仅使用 d {…}即只有一个参数但此时函数体无法使用索引。即使未使用到绑定的数据如需使用索引仍需要完整的写出 (d, i) {…}。 基于D3的基础语法与Data-Join绘制柱状图
数据来源 https://www.kaggle.com/gregorut/videogamesales Tip颜色 – ‘fill’属性
PlanA人为定义一系列颜色组合PlanB使用D3提供的颜色组合见下页PlanC采样 TipD3提供的各种色盘
定义一个离散数据到离散数据的映射 如每个水果对应到某个颜色 D3.js的内嵌自带配色方案 https://github.com/d3/d3-scale-chromatic 网络数据的数据结构
网络数据包括节点的集合与边的集合: 节点与边通常分布在不同的文件中通过节点的ID索引 D3.js也没有统一的网络数据结构规范 只要能整理成D3.js对应接口接受的格式即可 常见的数据形式 【节点列表】【连接矩阵】【节点数、边数与基于ID的连接】【节点列表】【边列表】
【节点数、边数与基于ID的连接】【节点列表】【边列表】 【连接矩阵】 d3力模拟基础
d3的力模拟与“transition”是完全不同的两个体系let nodes [{}, {}, {}, {}, {}, {}];let simulation d3.forceSimulation(nodes) 定义后会发生… 补全nodes中每个节点的数据结构 包括index, x, y, vx, vy后两者为速度。 开始模拟粒子运动 粒子质量为1。不断地通过内部timer触发’tick’事件。 根据一系列的‘力’来计算每个例子的加速度、速度、位置… ‘力’都是哪来的呢 不同力的作用
d3.forceManyBody().strength( value ) 粒子之间两两的作用力类似于‘万有引力’。.strength(value)’用来设置力的大小value为正互相吸引为负则互相排斥。 d3.forceCenter(w, h).strength( value ) 指向某一个中心的力会尽可能让粒子向中心靠近。.strength(…)的用法同上。‘d3.forceCenter(w, h)’中的‘w’与‘h’为中心的位置通常为画布的中心。 d3.forceLink(links).strength(strength).distance(distance) 部分粒子之间的两两作用力不同于‘d3.forceManyBody’。d3.forceLink’中每个节点仅仅会与一部分节点有力的作用。有链接的节点间受力的作用保持在特定的距离即靠近互斥、远离吸引。是否有链接需要通过图的边集合给出。‘.strength( vs )’ 与 ‘.distance( vd )’分别设置力的大小与预期的距离。 Link要通过一个数据格式给出即link的source与target。格式非常类似于‘d3.hierarchy’给出的root.links() 编程实例 ‘Tic-Toc’
forceSimulation会通过每次‘tick’来更新当前节点的状态 状态包括位置、速度、加速度等。 更新后的状态仅仅为‘状态’ 不会反映到任何图元仅修改数据。需要添加修改图元属性的回调函数。 人为设置每次tick要如何更新图元 simulation.on(‘tick’, ticked); 在初始化每个图元后只要为simulation配置了’tick’的回调simulation会自动开始模拟。 基于‘d3-force’实现力导图
数据来源http://networkrepository.com/socfb-Caltech36.php 编程实例 Tip带权重的图
d3.forceLink(links).strength(…).distance(…) 本质上根据link的权重设置forceLink的strength与distance。分别输入回调函数基于每一个‘link’元素来设置各自的力与距离。 编程实例