日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

数据可视化【七】 更新模式

發(fā)布時間:2023/11/30 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数据可视化【七】 更新模式 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Enter

以下面這個簡單的代碼進(jìn)行分析

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()以后相當(dāng)于選擇了上圖的Elements部分,data(fruits)相當(dāng)于上圖的Data部分,在一起以后就得到了上面的Data Join。然后我們再根據(jù)自己的需求選擇想要的部分進(jìn)行處理。

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

我們得到了集合以后就能使用append函數(shù)和attr函數(shù)進(jìn)行設(shè)置。

Exit

經(jīng)常我們綁定的數(shù)據(jù)發(fā)生變化以后我們想要對已經(jīng)不在數(shù)據(jù)集中的元素進(jìn)行處理。這個時候只需要再綁定一次數(shù)據(jù),然后對其中的exit()部分進(jìn)行設(shè)置即可。例如下面的例子:

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);

實(shí)現(xiàn)的效果就是原本屏幕上有五個點(diǎn),經(jīng)過一秒鐘以后最后一個點(diǎn)消失了。

Update

如果我們對數(shù)據(jù)中的一部分做了一些改動,又希望能夠在圖形中顯示出來,就可以在update中進(jìn)行修改。需要注意的是:在我們綁定數(shù)據(jù)以后默認(rèn)就是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

有時候我們需要對多個部分進(jìn)行相同的操作,當(dāng)然可以對每個部分都寫相同的代碼,只是那樣顯得有些繁瑣。我們可以使用merge()函數(shù)將多個selection進(jìn)行合并,傳入的參數(shù)是需要合并的部分。例如在上面的代碼中我們需要對enter和update都設(shè)置圓的半徑的顏色,我們就可以在enter后面合并update(update即就是綁定數(shù)據(jù)后的變量)。進(jìn)行修改以后就可以得到下面更加簡潔的代碼。

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()函數(shù)設(shè)置屬性,這樣屬性的變化就是漸進(jìn)的,我們可以同時設(shè)置duration(x)來設(shè)置變化需要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

在觀察上面代碼第三秒效果的時候我們會發(fā)現(xiàn),我們想要刪除第二個圓點(diǎn),實(shí)際上的效果卻是第二個圓點(diǎn)從紅色變成了黃色,然后變小了,第三個圓點(diǎn)變成了紅色然后變大了,第四個圓點(diǎn)消失了。這顯然不是我們想要的結(jié)果,我們想要的應(yīng)該是第二個圓點(diǎn)消失了,然后后面的圓點(diǎn)向前移動。

產(chǎn)生這種現(xiàn)象的原因在于d3中對數(shù)據(jù)唯一性的處理。默認(rèn)情況下d3是通過下標(biāo)唯一標(biāo)識數(shù)據(jù)的。因此產(chǎn)生上面現(xiàn)象的原因是我們修改數(shù)組以后,d3按照新數(shù)組的情況進(jìn)行了處理:第四個數(shù)據(jù)已經(jīng)沒有了,所以在exit里面進(jìn)行刪除,前面的屬性發(fā)生了變化然后直接進(jìn)行處理。

我們需要做的是幫助d3標(biāo)識不同的數(shù)據(jù),方法就是在綁定數(shù)據(jù)的時候使用data函數(shù)的數(shù)組后面再傳入一個函數(shù),用于標(biāo)識數(shù)據(jù)。

在這個實(shí)例中我們給原本的對象數(shù)組的每個元素添加新的屬性id,用來進(jìn)行區(qū)分,然后傳入的函數(shù)就是返回每個元素的id屬性。這樣d3就會將每個元素的id作為區(qū)分的標(biāo)準(zhǔn)。

代碼如下:
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) );

進(jìn)行上面的修改以后會發(fā)現(xiàn)效果的確是第二個圓點(diǎn)消失了,但是后面的圓點(diǎn)卻沒有向前移動。為了解決這個問題我們應(yīng)該將對位置的設(shè)置放在merge后的transition函數(shù)中,這樣每次綁定數(shù)據(jù)都會對enter和update中的元素設(shè)置位置。

代碼如下:
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

只有圓圈可能難以理解表達(dá)的是什么意思,我們就需要加上文字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元素設(shè)置文字內(nèi)容的函數(shù)是.text()

雖然上面的做法可行,但是當(dāng)有很多元素組合在一起的時候就有點(diǎn)力不從心。因此我們更常用的做法是將一組元素放在g中,然后再對g的位置屬性等進(jìn)行設(shè)置。

大概的做法就是先綁定數(shù)據(jù)以后給每個元素append一個g,然后再對g進(jìn)行操作。

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操作的時候都會對其中的每個元素進(jìn)行操作。特殊的,我們?nèi)绻胍砑右粋€唯一的元素的話可以綁定一個個數(shù)為一的數(shù)組,內(nèi)容可以隨意選定,一般情況下選擇[null]數(shù)組就比較好。然后在這個selection上進(jìn)行操作。

例如,我們想要給我們的動畫添加一個矩形的背景,就可以使用上面的方法添加一個。

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');

最后的效果圖(實(shí)際上應(yīng)該是動圖,這里沒有制作gif圖,可以在網(wǎng)站進(jìn)行查看)



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

總結(jié)

以上是生活随笔為你收集整理的数据可视化【七】 更新模式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。