动态散点图
数据
date,country,confirmed,recovered,death
1/31/20,IND,1,0,0
1/31/20,BRA,0,0,0
1/31/20,FRA,5,0,0
1/31/20,RUS,2,0,0
1/31/20,TUR,0,0,0
1/31/20,ARG,0,0,0
1/31/20,ITA,2,0,0
1/31/20,COL,0,0,0
1/31/20,ESP,0,0,0
1/31/20,GER,5,0,0
2/29/20,IND,3,3,0
2/29/20,BRA,2,0,0
2/29/20,FRA,100,12,2
2/29/20,RUS,2,2,0
2/29/20,TUR,0,0,0
2/29/20,ARG,0,0,0
2/29/20,ITA,1128,46,29
2/29/20,COL,0,0,0
2/29/20,ESP,45,2,0
2/29/20,GER,79,16,0
3/31/20,IND,1397,123,35
3/31/20,BRA,5717,127,201
3/31/20,FRA,51579,9444,3517
3/31/20,RUS,2337,121,17
3/31/20,TUR,13531,243,214
3/31/20,ARG,1054,240,27
3/31/20,ITA,105792,15729,12428
3/31/20,COL,906,31,16
3/31/20,ESP,95923,19259,8464
3/31/20,GER,71808,16100,775
4/30/20,IND,34863,9068,1154
4/30/20,BRA,87187,35935,6006
4/30/20,FRA,167326,48572,24315
4/30/20,RUS,106498,11619,1073
4/30/20,TUR,120204,48886,3174
4/30/20,ARG,4428,1256,218
4/30/20,ITA,205463,75945,27967
4/30/20,COL,6507,1439,293
4/30/20,ESP,213435,112050,24543
4/30/20,GER,163009,123500,6623
5/31/20,IND,190609,91852,5408
5/31/20,BRA,514849,206555,29314
5/31/20,FRA,187817,66123,28751
5/31/20,RUS,405843,171883,4693
5/31/20,TUR,163942,127973,4540
5/31/20,ARG,16851,5336,539
5/31/20,ITA,232997,157507,33415
5/31/20,COL,29383,7032,939
5/31/20,ESP,239479,150376,27127
5/31/20,GER,183410,165352,8540
6/30/20,IND,585481,347912,17400
6/30/20,BRA,1402041,788318,59594
6/30/20,FRA,196554,71714,29763
6/30/20,RUS,646929,411973,9306
6/30/20,TUR,199906,173111,5131
6/30/20,ARG,64530,22028,1307
6/30/20,ITA,240578,190248,34767
6/30/20,COL,97846,40021,3334
6/30/20,ESP,249271,150376,28355
6/30/20,GER,195418,178100,8990
7/31/20,IND,1695988,1094374,36511
7/31/20,BRA,2662485,2008854,92475
7/31/20,FRA,215135,71656,30150
7/31/20,RUS,838461,637217,13939
7/31/20,TUR,230873,214535,5691
7/31/20,ARG,191302,83780,3543
7/31/20,ITA,247537,199974,35141
7/31/20,COL,295508,154387,10105
7/31/20,ESP,288522,150376,28445
7/31/20,GER,210399,191992,9147
8/31/20,IND,3691166,2839882,65288
8/31/20,BRA,3908272,3268591,121381
8/31/20,FRA,304349,73537,30501
8/31/20,RUS,992402,807339,17128
8/31/20,TUR,270133,244926,6370
8/31/20,ARG,417735,301195,8660
8/31/20,ITA,269214,207653,35483
8/31/20,COL,615094,459460,19662
8/31/20,ESP,462858,150376,29094
8/31/20,GER,244802,216795,9303
9/30/20,IND,6312584,5273201,98678
9/30/20,BRA,4810935,4274774,143952
9/30/20,FRA,578769,79128,31761
9/30/20,RUS,1170799,954788,20630
9/30/20,TUR,318663,279749,8195
9/30/20,ARG,751001,594645,16937
9/30/20,ITA,314861,227704,35894
9/30/20,COL,829679,743653,25998
9/30/20,ESP,769188,150376,31791
9/30/20,GER,292913,256861,9495
10/31/20,IND,8184082,7491513,122111
10/31/20,BRA,5535605,5005161,159884
10/31/20,FRA,1374691,97475,36495
10/31/20,RUS,1606267,1208440,27787
10/31/20,TUR,375367,323971,10252
10/31/20,ARG,1166924,973939,31002
10/31/20,ITA,679430,289426,38618
10/31/20,COL,1074184,969230,31314
10/31/20,ESP,1185678,150376,35878
10/31/20,GER,531790,356410,10483
11/30/20,IND,9462809,8889585,137621
11/30/20,BRA,6335878,5597802,173120
11/30/20,FRA,2223393,139810,52383
11/30/20,RUS,2275936,1763493,39491
11/30/20,TUR,638847,404727,13746
11/30/20,ARG,1424533,1257227,38730
11/30/20,ITA,1601554,757507,55576
11/30/20,COL,1316806,1210489,36766
11/30/20,ESP,1648187,150376,45069
11/30/20,GER,1069912,749219,16694
12/31/20,IND,10286709,9883461,148994
12/31/20,BRA,7675973,6848844,194949
12/31/20,FRA,2616902,170426,64267
12/31/20,RUS,3127347,2527722,56271
12/31/20,TUR,2208652,2100650,20881
12/31/20,ARG,1625514,1426676,43245
12/31/20,ITA,2107166,1463111,74159
12/31/20,COL,1642775,1508419,43213
12/31/20,ESP,1928265,150376,50837
12/31/20,GER,1760520,1350708,33791
1/31/21,IND,10757610,10434983,154392
1/31/21,BRA,9204731,8176373,224504
1/31/21,FRA,3186354,199589,75673
1/31/21,RUS,3808348,3264611,72029
1/31/21,TUR,2477463,2362415,25993
1/31/21,ARG,1927239,1721650,47974
1/31/21,ITA,2553032,2010548,88516
1/31/21,COL,2094884,1938322,53983
1/31/21,ESP,2743119,150376,58319
1/31/21,GER,2225659,1940046,57163
2/28/21,IND,11112241,10786452,157157
2/28/21,BRA,10551259,9382316,254942
2/28/21,FRA,3732426,228299,85980
2/28/21,RUS,4198400,3769025,84700
2/28/21,TUR,2701588,2572234,28569
2/28/21,ARG,2107365,1905021,51965
2/28/21,ITA,2925265,2405199,97699
2/28/21,COL,2251690,2148249,59766
2/28/21,ESP,3188553,150376,69142
2/28/21,GER,2450295,2259548,70152
3/31/21,IND,12221665,11474683,162927
3/31/21,BRA,12748747,11181371,321515
3/31/21,FRA,4611392,264511,95052
3/31/21,RUS,4494234,4118709,97219
3/31/21,TUR,3317182,3014226,31537
3/31/21,ARG,2348821,2102616,55858
3/31/21,ITA,3584899,2913045,109346
3/31/21,COL,2406377,2285515,63422
3/31/21,ESP,3284353,150376,75459
3/31/21,GER,2843644,2539660,76589
4/30/21,IND,19164969,15684406,211853
4/30/21,BRA,14659011,12991951,403781
4/30/21,FRA,5571804,305692,103815
4/30/21,RUS,4750755,4377504,108290
4/30/21,TUR,4820591,4323897,40131
4/30/21,ARG,2977363,2634306,63865
4/30/21,ITA,4022653,3465576,120807
4/30/21,COL,2859724,2669308,73720
4/30/21,ESP,3524077,150376,78216
4/30/21,GER,3405365,3008640,83097
5/31/21,IND,28175044,25947629,331895
5/31/21,BRA,16545554,14586009,462791
5/31/21,FRA,5609558,332474,108700
5/31/21,RUS,5013512,4630461,119464
5/31/21,TUR,5249404,5114624,47527
5/31/21,ARG,3781784,3350602,78093
5/31/21,ITA,4217821,3858019,126128
5/31/21,COL,3406456,3169573,88774
5/31/21,ESP,3678390,150376,79953
5/31/21,GER,3689921,3498580,88601
6/30/21,IND,30411634,29488918,399459
6/30/21,BRA,18557141,16299258,518066
6/30/21,FRA,5707142,340159,110161
6/30/21,RUS,5449594,4942283,132973
6/30/21,TUR,5425652,5294285,49732
6/30/21,ARG,4470374,4076921,94304
6/30/21,ITA,4259909,4081902,127566
6/30/21,COL,4240982,3936156,106544
6/30/21,ESP,3808960,150376,80875
6/30/21,GER,3736205,3623800,90945
d3.js代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type='text/javascript' src='../Resources/lib/d3.js'></script>
</head>
<body>
<svg width='1200px' height='800px'></svg>
<script type='text/javascript'>
const margin = { top: 200, left: 500 }
const svg = d3.select('svg')
const g = svg.append('g').attr('transform', `translate(${margin.left}, ${margin.top})`)//整体变换
const dataset=new Array()//将数据处理后的一维数组
const shuju=new Array()//每个相同时间的10个国家数据放在一起的二维数组
d3.csv('../Resources/data/covid19.csv').then(async function (data) {
dataProcess(data)//数据处理函数
const barHeight = 400//条形图绘图区高度
const recovered=d3.map(dataset,d=>d.recovered)
const death=d3.map(dataset,d=>d.death)
const confirmed=d3.map(dataset,d=>d.confirmed)
const maxconfirmed=d3.max(confirmed)
const maxrecovered=d3.max(recovered)
const maxdeath=d3.max(death)
//绘制X轴和Y轴坐标系
const xScale = d3.scaleLinear([0, maxrecovered+5000000], [0, 600]).nice()
const yScale = d3.scaleLinear([0,maxdeath+100000], [barHeight,0])
const rScale=d3.scaleLinear([0,maxconfirmed], [0,50])
const xAxis = d3.axisBottom(xScale).ticks(7).tickSize(0).tickFormat(d3.format('.2s'))//X轴
const yAxis = d3.axisLeft(yScale).ticks(6).tickSize(0).tickFormat(d3.format('.2s'))//Y轴
g.append('g').attr('transform',`translate(0,${barHeight})`).call(xAxis)
g.append('g').call(yAxis);
//给坐标轴设置Recovered和Death文本
g.append('text').attr('transform',`translate(250,450)`).text('Recovered').call(xScale)
g.append('text').text('Death').attr('writing-mode','vertical-lr').attr('transform','translate(-80,190)').call(yScale)
//更新绘图函数
for(let i=0;i<shuju.length;i++){
await update(shuju[i])
}
//修改字体样式
d3.selectAll('text').attr('font-size', '14px').attr('font-weight','700')
function update(currData){
const transition = d3.transition().duration(5000).ease(d3.easeLinear)
//绘制散点并更新散点
const updatecircle=g.selectAll('circle').data(currData)
const entercircle=updatecircle.enter().append('circle')
.attr('cx',0)
.attr('cy',400)
.attr('r',0)
.attr('fill', (d, i) => d3.schemeCategory10[i])
updatecircle.merge(entercircle).transition(transition)
.attr('cx', d =>xScale(d.recovered))
.attr('cy', d =>yScale(d.death))
.attr('r',d=>rScale(d.confirmed))
//text文本并更新文本坐标
const updatetext=g.selectAll('#countrytext').data(currData)
const entertext=updatetext.enter()
.append('text')
.attr('id','countrytext')
.attr('x',0)
.attr('y',400)
const mergeText=updatetext.merge(entertext).transition(transition)
.attr('x', d =>xScale(d.recovered))
.attr('y', d =>yScale(d.death))
.text(d=>d.country)
}
})
function dataProcess(data){
let k=0,i=0
for(let i=0;i<18;i++) shuju[i]=new Array()
data.forEach(row => {//数组遍历
i++
const { confirmed, country, date, death, recovered } = row//解构赋值
const obj = {}
obj.date = new Date(date)//生成日期对象
obj.country = country
obj.confirmed = +confirmed//转换为数值
obj.recovered = +recovered
obj.death = +death
dataset.push(obj)
shuju[k].push(obj)
if(i>9) {i=0,k++;}
})
}
</script>
</body>
</html>