數據可視化【七】 更新模式

在這里插入圖片描述

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

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/383611.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/383611.shtml
英文地址,請注明出處:http://en.pswp.cn/news/383611.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

數據可視化【八】根據數據類型選擇可視化方式

Marks:Rows PointsLinesAreas Channels:Columns PositionColorShape

數據可視化【九】單向數據流交互

我們使用一下上上篇博客的代碼。 例如我們想要當鼠標點擊水果的時候會出現黑色的框,再點擊一下黑色的框就會消失。 首先,我們應該給組件添加點擊事件: fruitBowl.js gruopAll.on(click, d > onClick(d.id));這個on函數第一個參數是事件…

數據庫原理及應用【四】數據庫管理系統

查詢優化 數據庫管理系統中非常重要的一部分。 代數優化 按照一定的規則將語句變化成關系代數以后進行優化 操作優化 對代數優化后的查詢樹使用比較好的方法進行查詢。 主要是對連接運算進行優化 嵌套循環歸并掃描索引優化哈希連接 恢復機制 備份(完整備份差…

數據庫原理及應用【五】安全性和完整性約束

數據庫一致性被破壞: 系統故障許多用戶的并發訪問人為破壞事務本身不正確 保護數據庫一致性的方法: 視圖/查詢修改訪問控制 普通用戶擁有資源特權的用戶DBA 數據庫的安全問題 身份驗證 口令物理設備 GRANT CONNECT TO John IDENTIFIED BY 123456…

遞歸式復雜度求解

代換法 猜測復雜度驗證是否滿足遞歸式(使用歸納法)找到常數應該滿足的條件針對基本情況,常數足夠大時總是成立的 需要注意的是,我們猜測的復雜度有可能不滿足遞歸式,這個時候就要通過減去一些低階項來使得歸納成立。…

斐波那契數列計算

定義 斐波那契數列: F[n]{0,n01,n1F[n?1]F[n?2],elseF[n] \begin{cases} 0,n0 \\ 1,n1\\ F[n-1]F[n-2],else \end{cases} F[n]??????0,n01,n1F[n?1]F[n?2],else? 樸素計算法 根據遞歸式F[n]F[n?1]F[n?2]F[n]F[n-1]F[n-2]F[n]F[n?1]F[n?2]進行計算…

P、NP、NP完全問題、NP難問題

可以在多項式時間內求解的問題稱為易解的,而不能在多項式時間內求解的問題稱為難解的。 P類問題:多項式類型,是一類能夠用(確定性的)算法在多項式的時間內求解的判定問題。 只有判定問題才屬于P 不可判定問題&#…

數據可視化【十】繪制地圖

Loading and parsing TOPOJSON 導入Topojson d3文件 地址:https://unpkg.com/topojson3.0.2/dist/topojson.min.js 想要找d3文件的話去unpkg.com好像大部分都能找到的樣子 Rendering geographic features 尋找合適的地圖數據:谷歌搜索world-atlas npm…

數據可視化【十一】樹狀圖

Constructing a node-link tree visualization 首先將節點之間的連線畫出來。 使用json函數讀取文件以后,使用hierarchy等函數得到連線的數組,然后綁定這個數組,給每個元素添加一個path,繪畫使用的是一個函數linkHorizontal&…

數據可視化【十二】 顏色圖例和尺寸圖例

有了前面的知識,制作一個圖例應該不是很難,關鍵是我們想要制作一個可以在其他地方進行使用的圖例,這樣就需要能夠動態地設置圖例的大小,位置,等等。 這里直接上代碼: colorLegend.js export const color…

數據可視化【十三】地區分布圖

在前面的博客中已經介紹了如何繪制地圖,這一節學習如何繪制地區分布圖。如果對繪制地圖還不熟悉的話可以了解一下之前我寫的博客:數據可視化【十】繪制地圖 Intergrating(整合) TopoJSON with tabular data(列表數據) 在前面的博客中沒有使用到tsv文件…

3.01【python正則表達式以及re模塊】

python正則表達式以及re模塊 元字符 正則表達式的語法就由表格中的元字符組成,一般用于搜索、替換、提取文本數據 元字符含義.匹配除換行符以外的任何單個字符*匹配前面的模式0次或1次匹配前面的模式1次或多次?匹配前面的模式0次或1次[]用于定義字符集&#xff…

Linux配置編程環境+云服務器上傳文件

Java環境配置 Ubuntu https://www.cnblogs.com/lfri/p/10437266.html Centos https://blog.csdn.net/qq_21077715/article/details/85536399 Tomcat配置 Centos https://blog.csdn.net/qq_21077715/article/details/85541685 https://www.cnblogs.com/newwind/p/9904561…

gbd + cgbd

gbd:傳送門 cgbd:傳送門 | 傳送門

數據可視化【十四】交互式過濾地區分布圖

在前面的博客中已經介紹了如何繪制地區分布圖,這一節學習如何繪制交互式過濾地區分布圖。如果對繪制地區分布圖還不熟悉的話可以了解一下之前我寫的博客:數據可視化【十三】地區分布圖 整體的框架仍然是在之前的基礎上進行修改,主要是添加交…

Ubuntu環境搭建

本文記錄了一些常用的Ubuntu軟件 然后首先修改軟件源:軟件和更新->Ubuntu軟件->下載自:其他站點(修改為阿里云) 在關閉的時候需要更新什么的 然后修改更新方式,將不支持的更新去掉 常用的Windows軟件 網易云…

1 兩數之和

雖然只是一道很簡單的題,但是也給我很多思考。 剛看到這道題的時候沒有仔細思考,直接寫了個排序和二分查找,想著對每個數字查找另一個數字會不會出現,復雜度是O(nlognnlogn)O(nlognnlogn)O(nlognnlogn),主要訓練了一下…

834 樹中距離之和

這道題我自己的想法只有對每個點都用一遍Dijkstra然后再求和,顯然會超時,所以我都沒有嘗試。 研究了一下題解,發現題解很巧妙,自己對樹的處理還是太稚嫩,之前樹鏈剖分學的都忘光了。 對于固定根節點的,我…

75 顏色分類

題目已經提示可以一遍掃描了但是我還是沒有想到,其實雙指針的想法我已經有了,但是一想到有問題就覺得無法實現。這也揭示了我思維上的問題:用一種方法解決問題遇到困難第一件事情不是想著如何攻克而是想著換一種方法。對自己的思維也不自信。…

141 環形鏈表

要求使用空間復雜度為O(1)的方法,可是我并沒有想到。我想到的只有用一個哈希表記錄一下所有訪問過的節點。 題解給出的空間復雜度為O(1)的方法是使用兩個指針,然后讓一個一次跑一步,一個一次跑兩步,如果跑的快的能追上跑的慢的就…