1. 程式人生 > >再論HTML散點圖(Scatter Plot)的SVG實現方式

再論HTML散點圖(Scatter Plot)的SVG實現方式

介紹

在上一篇《HTML散點圖(Scatter Plot)的三種不同實現方式效能比較》中,重點比較了散點圖的SVG實現方式和HTML5 Canvas實現方式的不同。這兒再詳細看看使用SVG,預先生成節點和實時載入資料之間的區別。

這兒為了在效能上有所比較,因此將散點數目增加到250,000,並且用於繪製散點的csv檔案由data-generator.py統一生成。原始碼可在此處下載。

data-generator.py

import pandas as pd
import numpy as np

df = pd.DataFrame(np.random.randint(0,500,size=(250000, 2)), columns=list('xy'))
df.to_csv('./data.csv',index=False)


實現方式

1. 預先用後端程式碼在HTML頁面中生成250000個<circle>節點

pre-render-with-csv.js

var el = window.document.querySelector('#dataviz-container')
			, body = window.document.querySelector('body')
			, circleId = 'a2324'  // say, this value was dynamically retrieved from some database

		
		//load data from csv file
		//d3.csv('data.csv', function(data){
		fs.readFile('data.csv', 'utf8', function (err, data) {
			data = d3.csvParse(data);
			
			data.forEach(function(d){
			    d.x = +d.x;
			    d.y = +d.y;
			});
			console.log(data.length);
			// generate the dataviz
			var svg = d3.select(el)
				.append('svg:svg')
					.attr('width', 500)
					.attr('height', 500);

			svg.selectAll('.circle')
				.data( data )
				.enter()
					.append('circle')
					.attr('r', 1)
					.attr('fill', '#26963c')
					.attr('cx', function(d){return d.x;})
	    			.attr('cy', function(d){return d.y;});

	    	// save result in an html file, we could also keep it in memory, or export the interesting fragment into a database for later use
			var svgsrc = window.document.documentElement.innerHTML;
			fs.writeFile('index-svg-d3-csv-pre-render.html', svgsrc, function(err) {
				if(err) {
					console.log('error saving document', err);
				} else {
					console.log('The file was saved!');
				}
			});
		});


2. 預先用後端程式碼在HTML頁面中生成100000個<circle>節點。剩餘的節點用d3.js程式碼在頁面載入時實時生成

index-svg-d3-csv-partial-render.html

程式碼除了有預先存在的100000個<circle>節點之外,其他程式碼與index-svg-d3-csv.html相同。

3. 所有250000個<circle>節點用d3.js程式碼在頁面載入時實時生成

index-svg-d3-csv.html

		//load data from csv file
		d3.csv('data.csv', function(data){
			data.forEach(function(d){
			    d.x = +d.x;
			    d.y = +d.y;
			});

			// generate the dataviz
			var svg = d3.select('#dataviz-container')
				.append('svg:svg')
					.attr('width', 500)
					.attr('height', 500);

			svg.selectAll('.circle')
				.data( data )
				.enter()
					.append('circle')
					.attr('r', 1)
					.attr('fill', '#26963c')
					.attr('cx', function(d){return d.x;})
	    			.attr('cy', function(d){return d.y;});
			});

結果比較

由於三種實現的最後呈現效果一樣,主要就是看一下效能,即頁面的載入時間,見圖1。

如果從最終載入完畢的時間來看,第3種實現用時最短,第1種用時最長。與上一篇部落格裡的觀察一致。由於伺服器就在本地,因此載入csv檔案的時間可以忽略不計。

如果從一開始出現散點來看,則是第1種用時最短,第3種用時最長。

從總體效能來看,如果將散點的數量增加到1,000,000,則載入用時將會達到40秒以上。顯然,從使用者體驗來看,幾十萬的散點圖效能將會超過個人所能忍受的程度。但如果能像第1種實現和第2種實現那樣提前顯示一部分散點,將會有效改善使用者體驗。

第2種實現和第1種相比,犧牲了一部分提前顯示散點的時間,但降低了HTML頁面的大小。


圖1