Enter

以下面这个简单的代码进行分析

const svg = d3.select('svg');
// svg.style('background-color', 'red'); testconst height = +svg.attr('height');
//+ equals paresFloat()
const width = +svg.attr('width');const makeFruit = type =>( {type} );  //这种写法好像能够直接得到一个属性名为'type',值为变量type值的对象const fruits = d3.range(5).map(() => makeFruit('apple') );// console.log(fruits);svg.selectAll('circle').data(fruits).enter().append('circle').attr('cx', (d,i) => i*100+10).attr('cy', height/2).attr('r', 10).attr('fill', 'red');

在选择selectAll()以后相当于选择了上图的Elements部分,data(fruits)相当于上图的Data部分,在一起以后就得到了上面的Data Join。然后我们再根据自己的需求选择想要的部分进行处理。

  • Enter 是不在Elements中的Data中的元素的集合
  • Update是既在Elments集合中又在Data集合中的元素集合
  • Exit是仅在Elements集合中的元素集合

我们得到了集合以后就能使用append函数和attr函数进行设置。

Exit

经常我们绑定的数据发生变化以后我们想要对已经不在数据集中的元素进行处理。这个时候只需要再绑定一次数据,然后对其中的exit()部分进行设置即可。例如下面的例子:

const svg = d3.select('svg');
// svg.style('background-color', 'red'); testconst height = +svg.attr('height');
//+ equals paresFloat()
const width = +svg.attr('width');const render = (selection, { fruits }) => {const circles = selection.selectAll('circle').data(fruits);circles.enter().append('circle').attr('cx', (d,i) => i*100+10).attr('cy', height/2).attr('r', 10).attr('fill', 'red');circles.exit().remove();// .attr('fill', 'black');
}const makeFruit = type =>( {type} );  //这种写法好像能够直接得到一个属性名为'type',值为变量type值的对象const fruits = d3.range(5).map(() => makeFruit('apple') );render(svg, { fruits } );// console.log(fruits);setTimeout(()=>{fruits.pop();render(svg, { fruits } );
}, 1000);

实现的效果就是原本屏幕上有五个点,经过一秒钟以后最后一个点消失了。

Update

如果我们对数据中的一部分做了一些改动,又希望能够在图形中显示出来,就可以在update中进行修改。需要注意的是:在我们绑定数据以后默认就是update集合。例如:

const svg = d3.select('svg');
// svg.style('background-color', 'red'); testconst height = +svg.attr('height');
//+ equals paresFloat()
const width = +svg.attr('width');const colorScale = d3.scaleOrdinal().domain(['apple', 'lemon']).range(['red', 'yellow']);const radiusScale = d3.scaleOrdinal().domain(['apple', 'lemon']).range([50, 20]);const render = (selection, { fruits }) => {const circles = selection.selectAll('circle').data(fruits);circles.enter().append('circle').attr('cx', (d,i) => i*150+50).attr('cy', height/2).attr('r', d => radiusScale(d.type)).attr('fill', d => colorScale(d.type) );circles.exit().remove();// .attr('fill', 'black');circles.attr('cx', (d,i) => i*150+50).attr('cy', height/2).attr('r', d => radiusScale(d.type)).attr('fill', d => colorScale(d.type) );
}const makeFruit = type =>( {type} );  //这种写法好像能够直接得到一个属性名为'type',值为变量type值的对象const fruits = d3.range(5).map(() => makeFruit('apple') );render(svg, { fruits } );// console.log(fruits);setTimeout(()=>{fruits.pop();render(svg, { fruits } );
}, 1000);setTimeout(()=>{fruits[2].type = 'lemon';render(svg, { fruits } );
}, 2000);

最终的效果:

Merge

有时候我们需要对多个部分进行相同的操作,当然可以对每个部分都写相同的代码,只是那样显得有些繁琐。我们可以使用merge()函数将多个selection进行合并,传入的参数是需要合并的部分。例如在上面的代码中我们需要对enterupdate都设置圆的半径的颜色,我们就可以在enter后面合并updateupdate即就是绑定数据后的变量)。进行修改以后就可以得到下面更加简洁的代码。

fruitBowl.js

const colorScale = d3.scaleOrdinal().domain(['apple', 'lemon']).range(['red', 'yellow']);const radiusScale = d3.scaleOrdinal().domain(['apple', 'lemon']).range([50, 20]);export const fruitBowl = (selection, props) => {const {fruits, height} = props;const circles = selection.selectAll('circle').data(fruits);circles.enter().append('circle').attr('cx', (d,i) => i*150+50).attr('cy', height/2).merge(circles) //both enter section and update section.attr('r', d => radiusScale(d.type)).attr('fill', d => colorScale(d.type));circles.exit().remove();// .attr('fill', 'black');}

index.js

import { fruitBowl } from './fruitBowl.js';const svg = d3.select('svg');
// svg.style('background-color', 'red'); testconst makeFruit = type =>( {type} );  //这种写法好像能够直接得到一个属性名为'type',值为变量type值的对象let fruits = d3.range(5).map(() => makeFruit('apple') );const render = () => {fruitBowl(svg, {fruits, height : +svg.attr('height')})
};render();// console.log(fruits);setTimeout(()=>{fruits.pop();render();
}, 1000);setTimeout(()=>{fruits[2].type = 'lemon';render();
}, 2000);setTimeout(()=>{fruits = fruits.filter((d, i) => i!=1);render();
}, 3000);

Animated Transitions(动画过渡)

为了添加动画效果我们可以使用transition()函数设置属性,这样属性的变化就是渐进的,我们可以同时设置duration(x)来设置变化需要x ms。例如:

const colorScale = d3.scaleOrdinal().domain(['apple', 'lemon']).range(['red', 'yellow']);const radiusScale = d3.scaleOrdinal().domain(['apple', 'lemon']).range([50, 20]);export const fruitBowl = (selection, props) => {const {fruits, height} = props;const circles = selection.selectAll('circle').data(fruits);circles.enter().append('circle').attr('cx', (d,i) => i*150+50).attr('cy', height/2).attr('r', 0).merge(circles)  //both enter section and update section.attr('fill', d => colorScale(d.type)).transition().duration(1000).attr('r', d => radiusScale(d.type));circles.exit().transition().duration(1000).attr('r', 0).remove();// .attr('fill', 'black');
}

Object constancy

在观察上面代码第三秒效果的时候我们会发现,我们想要删除第二个圆点,实际上的效果却是第二个圆点从红色变成了黄色,然后变小了,第三个圆点变成了红色然后变大了,第四个圆点消失了。这显然不是我们想要的结果,我们想要的应该是第二个圆点消失了,然后后面的圆点向前移动。

产生这种现象的原因在于d3中对数据唯一性的处理。默认情况下d3是通过下标唯一标识数据的。因此产生上面现象的原因是我们修改数组以后,d3按照新数组的情况进行了处理:第四个数据已经没有了,所以在exit里面进行删除,前面的属性发生了变化然后直接进行处理。

我们需要做的是帮助d3标识不同的数据,方法就是在绑定数据的时候使用data函数的数组后面再传入一个函数,用于标识数据。

在这个实例中我们给原本的对象数组的每个元素添加新的属性id,用来进行区分,然后传入的函数就是返回每个元素的id属性。这样d3就会将每个元素的id作为区分的标准。

代码如下:
fruitBowl.js

const circles = selection.selectAll('circle').data(fruits,  d => d.id);

index.js

const makeFruit = (type, i) =>( {type,id : i
} );    //这种写法好像能够直接得到一个属性名为'type',值为变量type值的对象let fruits = d3.range(5).map((d,i) => makeFruit('apple', i) );

进行上面的修改以后会发现效果的确是第二个圆点消失了,但是后面的圆点却没有向前移动。为了解决这个问题我们应该将对位置的设置放在merge后的transition函数中,这样每次绑定数据都会对enterupdate中的元素设置位置。

代码如下:
fruitBowl.js

const colorScale = d3.scaleOrdinal().domain(['apple', 'lemon']).range(['red', 'yellow']);const radiusScale = d3.scaleOrdinal().domain(['apple', 'lemon']).range([50, 20]);const xPosition = (d,i) => i*150+50;export const fruitBowl = (selection, props) => {const {fruits, height} = props;const circles = selection.selectAll('circle').data(fruits,  d => d.id);circles.enter().append('circle').attr('cy', height/2).attr('cx', xPosition).attr('r', 0).merge(circles) //both enter section and update section.attr('fill', d => colorScale(d.type)).transition().duration(1000).attr('cx', xPosition).attr('r', d => radiusScale(d.type));circles.exit().transition().duration(1000).attr('r', 0).remove();// .attr('fill', 'black');}

vizhub 代码:https://vizhub.com/Edward-Elric233/1a1bd422d4b349aba1735868ff453b5f

Nested(嵌套的) elements

只有圆圈可能难以理解表达的是什么意思,我们就需要加上文字text
fruitBowl.js

const colorScale = d3.scaleOrdinal().domain(['apple', 'lemon']).range(['red', 'yellow']);const radiusScale = d3.scaleOrdinal().domain(['apple', 'lemon']).range([50, 20]);const xPosition = (d,i) => i*150+50;export const fruitBowl = (selection, props) => {const {fruits, height} = props;const circles = selection.selectAll('circle').data(fruits,  d => d.id);circles.enter().append('circle').attr('cy', height/2).attr('cx', xPosition).attr('r', 0).merge(circles) //both enter section and update section.attr('fill', d => colorScale(d.type)).transition().duration(1000).attr('cx', xPosition).attr('r', d => radiusScale(d.type));circles.exit().transition().duration(1000).attr('r', 0).remove();// .attr('fill', 'black');const text = selection.selectAll('text').data(fruits,  d => d.id);text.enter().append('text').attr('y', height/2+100).attr('x', xPosition).merge(text) //both enter section and update section.text(d => d.type).transition().duration(1000).attr('x', xPosition);text.exit().remove();
}

styles.css

text {font-size: 1.2em;text-anchor : middle;
}

注意text元素设置文字内容的函数是.text()

虽然上面的做法可行,但是当有很多元素组合在一起的时候就有点力不从心。因此我们更常用的做法是将一组元素放在g中,然后再对g的位置属性等进行设置。

大概的做法就是先绑定数据以后给每个元素append一个g,然后再对g进行操作。

const colorScale = d3.scaleOrdinal().domain(['apple', 'lemon']).range(['red', 'yellow']);const radiusScale = d3.scaleOrdinal().domain(['apple', 'lemon']).range([50, 20]);const xPosition = (d,i) => i*150+50;export const fruitBowl = (selection, props) => {const {fruits, height} = props;const groups = selection.selectAll('g').data(fruits,  d => d.id);const groupEnter = groups.enter().append('g').attr('transform', (d,i) => `translate(${i*150+50}, ${height/2})`);;groupEnter.merge(groups) //both enter section and update section.transition().duration(1000).attr('transform', (d,i) => `translate(${i*150+50}, ${height/2})`);groups.exit().select('circle').transition().duration(1000).style('fill', 'white').attr('r',0)setTimeout(() => groups.exit().select('circle').remove(),1000);// .attr('fill', 'black');groups.exit().select('text').transition().duration(1000).attr('fill', 'white');setTimeout(() => groups.exit().select('text').remove(), 1000);groupEnter.append('circle').attr('r', 0).merge(groups.select('circle'))   //both enter section and update section.attr('fill', d => colorScale(d.type)).transition().duration(1000).attr('r', d => radiusScale(d.type));const text = groups.select('text');groupEnter.append('text').attr('y', 100).merge(text)    //both enter section and update section.text(d => d.type)}

vizhub代码:https://vizhub.com/Edward-Elric233/f33fac2e32134707896521d420d5e255

Singular elements

每次我用对selection操作的时候都会对其中的每个元素进行操作。特殊的,我们如果想要添加一个唯一的元素的话可以绑定一个个数为一的数组,内容可以随意选定,一般情况下选择[null]数组就比较好。然后在这个selection上进行操作。

例如,我们想要给我们的动画添加一个矩形的背景,就可以使用上面的方法添加一个。

const bowl = selection.selectAll('rect').data([null]).enter().append('rect').attr('y', 110).attr('width', 700).attr('height', 300).attr('rx', 300/2) //圆角矩形.attr('fill', '#ebfbfc');

最后的效果图(实际上应该是动图,这里没有制作gif图,可以在网站进行查看)



vizhub代码:https://vizhub.com/Edward-Elric233/bc54edb3b722482590f498f3a1047a62

数据可视化【七】 更新模式相关推荐

  1. 试衣模式是如何打破传统数据可视化软件开发模式

    2018年8月6日,是一个特别的日子,这一天,一款足够载入数据可视化BI工具历史的工具--- 云蛛系统横空出世.其不仅可以像其他产品一样提供全套产品化的东东,而且还可以像项目一样,帮用户进行定制化!一 ...

  2. 【Python数据可视化(七)】使用正确的图表理解数据

    文章目录 对数图 频谱图 创建火柴杆图 绘制矢量场流线图 绘制风杆(barbs) 使用颜色表 使用散点图和直方图 绘制两个变量间的互相关图形 自相关地重要性 绘制甘特图 使用文本和字体属性 用LaTe ...

  3. python 可视化界面_工具推荐 | 3维数据可视化

    高维数据是一种非常常见的数据类型,其中包含了多种属性.比如:数值模式输出结果通常包含多种物理参量及多个时次,还有一些空间位置信息.尽管高维数据非常常见,但是高维数据的分析一直是个挑战.那么如何才能有效 ...

  4. 交互式数据可视化的优势

    数据可视化基本上就是使用可视化元素来描述数据的重要性.它是业务分析的重要部分,可以采用表格.图形.图表等形式.数据可视化使业务主管和关键决策者(尤其是那些没有计算机科学或统计分析背景的人)能够更快地理 ...

  5. 为什么Python是数据可视化编程的最佳选择?

    前言 统计信息的图形显示被称为数据可视化.编程数据可视化工具提供了一种直接的方法,通过利用图表.图形和地图等视觉组件来检查和理解数据中的趋势.异常值和模式.(文末送福利) [Python]提供的[数据 ...

  6. 交互式数据可视化的7个主要优势

    全世界每时每刻都在以令人难以置信的速度生成大量数据.在过去的几年中,全球每年的数据生产速度一直很高.事实上,2019年,世界上创建.捕获.复制和消费的数据总量达到了约41 Zettabytes,而20 ...

  7. 大数据可视化(七)复杂数据可视化

    第七章 复杂数据可视化 复杂的数据包括视频影像数据,传感器网络数据,社交网络数据,三维时空数据等. 对高维多元数据进行分析的困难如下: (1) 数据复杂度大大增加 (2) 数据的量级已经超过了单机,甚 ...

  8. vue 雷达扫描_GitHub - suneildve/vueDataV: 基于Vue + Echarts 构建的数据可视化平台,酷炫大屏展示模板和组件库,持续更新各行各业实用模板和炫酷小组件。...

    前言 一个基于Vue前端框架和第三方图表库echarts构建的可视化大数据平台,通过vue项目构建.指令的灵活运用.组件封装.组件之间通信,使内部图表组件库可实现自由替换和组合. 项目中部分前端库采用 ...

  9. Python数据可视化案例二:动态更新数据

    在开发与数据监测和数据可视化有关的系统时,我们会需要根据最新的数据对图形进行更新.下面的代码模拟了这种情况,单击Start按钮时会更新数据并重新绘制图形使得曲线看上去在移动一样,单击Stop按钮则停止 ...

  10. 《七天数据可视化之旅》第七天:可视化设计实战-数据大屏

    <七天数据可视化之旅>第七天:可视化设计实战-数据大屏 Destiny,某物流公司数据产品经理,目前从事数据平台搭建和可视化相关的工作.持续学习中,期望与大家多多交流数据相关的技术和实际应 ...

最新文章

  1. eclipse 关联 Maven本地仓库的配置
  2. Cisco OSPF常见问题
  3. VSLAM与SLAM联手应对数十万台巡检机器人商机
  4. 在Eclipse中使用JUnit4进行单元测试(中级篇)
  5. [密码学] DES(二)
  6. Windows Mobile (EVC)开发手记1
  7. Parity 錢包合約漏洞
  8. flink web ui提交任务时出现Server Respoonse Message-Internal server error
  9. python计算N维数据的笛卡尔积
  10. java 多个项目间事物_Java-web-多个独立项目之间相互调用实践
  11. 华为认证 HCNA­Cloud 云计算题库
  12. 【解决:Failed to execute goal org.apache.tomcat.maven:tomcat7-maven-plugin:2....Could not star】
  13. java 判断正态分布_如何检验数据是否服从正态分布
  14. 在openEuler上搭建LFS
  15. Git commit --amend
  16. ligerui demo php,LigerUI——天外飞仙
  17. c语言中switch的参数,C语言 switch 语句-嗨客网
  18. python爬虫接单发源地_python爬虫任务接单渠道
  19. Linux搜索查找命令【详细整理】
  20. SPA项目开发 之 登录注册

热门文章

  1. 埃及分数The Rotation Game骑士精神——IDA*
  2. LintCode 387: Smallest Difference
  3. 构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(44)-工作流设计-设计表单...
  4. Request 分别获取具有相同 name 属性表单元素值
  5. Gridview一次更新所有记录
  6. SYBASE灾难备份方案
  7. hdp安装 不安装mysql_hdp安装及使用问题汇总(一)
  8. javafx android sdk,JavaFX打包到Android上
  9. tf 如何进行svd_Tensorflow快餐教程(6) - 矩阵分解
  10. python去掉重复内容并按原来次序输出元素_在Python中,从列表中删除重复项以使所有元素在保留顺序时都是唯一的最快的算法是什么?...