I have written a code in d3.js to create an animated 2-d scatterplot to show how the income and life expectancy has changed in the US from 1980-2018 for different races (white, black, all races). I want to now make this 3-d. Please help me think of ideas on how I can do it the easiest way: 

/\*
\* main.js
\* Mastering Data Visualization with D3.js
\* Project 2 - Gapminder Clone
\*/

const MARGIN = { LEFT: 100, RIGHT: 10, TOP: 10, BOTTOM: 100 }
const WIDTH = 800 - MARGIN.LEFT - MARGIN.RIGHT
const HEIGHT = 500 - MARGIN.TOP - MARGIN.BOTTOM

const svg = d3.select("#chart-area").append("svg")
 .attr("width", WIDTH + MARGIN.LEFT + MARGIN.RIGHT)
 .attr("height", HEIGHT + MARGIN.TOP + MARGIN.BOTTOM)

const g = svg.append("g")
 .attr("transform", `translate(${MARGIN.LEFT}, ${MARGIN.TOP})`)

let time = 0

// Select the slider element
const slider = d3.select("#slider")

// Attach an event listener to the slider
slider.on("input", function() {
 // Update the time variable based on the slider value
 time = +this.value

 // Update the visualization with the new data
 update(formattedData[time])

 // Update the time label
 timeLabel.text(String(time + 1980))
})
// Scales
const x = d3.scaleLog()
 .base(10)
 .range([0, WIDTH])
 .domain([30000, 80000])
const y = d3.scaleLinear()
 .range([HEIGHT, 0])
 .domain([60, 90])

// Labels
const xLabel = g.append("text")
 .attr("y", HEIGHT + 50)
 .attr("x", WIDTH / 2)
 .attr("font-size", "20px")
 .attr("text-anchor", "middle")
 .text("Median Family Income ($)")
const yLabel = g.append("text")
 .attr("transform", "rotate(-90)")
 .attr("y", -40)
 .attr("x", -170)
 .attr("font-size", "20px")
 .attr("text-anchor", "middle")
 .text("Life Expectancy (Years)")
const timeLabel = g.append("text")
 .attr("y", HEIGHT - 10)
 .attr("x", WIDTH - 40)
 .attr("font-size", "40px")
 .attr("opacity", "0.4")
 .attr("text-anchor", "middle")
 .text("1980")

// X Axis
const xAxisCall = d3.axisBottom(x)
 .tickValues([30000,40000,50000,60000,70000,80000])
 .tickFormat(d3.format("$"));
g.append("g")
 .attr("class", "x axis")
 .attr("transform", `translate(0, ${HEIGHT})`)
 .call(xAxisCall)

// Y Axis
const yAxisCall = d3.axisLeft(y)
 .tickValues([60,65,70,75,80,85,90])
g.append("g")
 .attr("class", "y axis")
 .call(yAxisCall)

d3.json("data/current\_data.json").then(function(data){
 // clean data
 const formattedData = data.map(year => {
 return year["races"].filter(race => {
 const dataExists = (race.income && race.life\_exp)
 return dataExists
 }).map(race => {
 race.income = Number(race.income)
 race.life\_exp = Number(race.life\_exp)
 return race
 })
 })

 // run the code every 0.1 second
 d3.interval(function(){
 time = (time < formattedData.length-1) ? time + 1 : 0 
 update(formattedData[time])
 timeLabel.text(String(time + 1980))
}, 200)

 // first run of the visualization
 update(formattedData[0])
})

function update(data) {
 // standard transition time for the visualization
 const t = d3.transition()
 .duration(500)
 .ease(d3.easeLinear)

 

 // JOIN new data with old elements.
 const circles = g.selectAll("circle")
 .data(data, d => d.race)

 // EXIT old elements not present in new data.
 circles.exit().remove()

 // ENTER new elements present in new data.
 circles.enter().append("circle")
 .attr("fill", d => {
 if (d.race === "white") {
 return "pink";
 } else if (d.race === "black") {
 return "black";
 } else if (d.race === "all") {
 return "blue";}
})
 .merge(circles)
 .transition(t)
 .attr("cy", d => y(d.life\_exp))
 .attr("cx", d => x(d.income))
 .attr("r", 25)

 // update the time label
 timeLabel.text(String(time + 1980))
 }
1980년부터 2018년까지 미국에서 다양한 인종(백인, 흑인, 모든 인종)의 소득과 기대 수명이 어떻게 변화했는지 보여주는 애니메이션 2D 분산형 차트를 만드는 코드를 d3.js로 작성했습니다. 이제 이것을 3D로 만들고 싶습니다. 가장 쉬운 방법에 대한 아이디어를 생각하도록 도와주세요: /\*\* main.js\* D3.js로 데이터 시각화 마스터하기\* 프로젝트 2 - 갭마인더 클론 만들기\*/const MARGIN = { LEFT: 100, RIGHT: 10, TOP: 10, BOTTOM: 100 }const WIDTH = 800 - MARGIN.LEFT - MARGIN.RIGHTconst HEIGHT = 500 - MARGIN.TOP - MARGIN.BOTTOMconst svg = d3.select("#chart-area").append("svg") .attr("width", WIDTH + MARGIN.LEFT + MARGIN.RIGHT) .attr("height", HEIGHT + MARGIN.TOP + MARGIN.BOTTOM)const g = svg.append("g") .attr("transform", `translate(${MARGIN.LEFT}, ${MARGIN.TOP})`)let time = 0// 슬라이더 요소 선택const slider = d3.select("#슬라이더")// 슬라이더에 이벤트 리스너를 붙입니다.slider.on("input", function() { // 슬라이더 값에 따라 시간 변수를 업데이트합니다. time = +this.value // 새 데이터로 시각화를 업데이트합니다. update(formattedData[time]) // 시간 레이블을 업데이트합니다. timeLabel.text(String(time + 1980))})// 스케일const x = d3.scaleLog() .base(10) .range([0, WIDTH]) .domain([30000, 80000])const y = d3.scaleLinear() .range([HEIGHT, 0]) .domain([60, 90])// 라벨const xLabel = g.append("text") .attr("y", HEIGHT + 50) .attr("x", WIDTH / 2) .attr("font-size", "20px") .attr("텍스트-앵커", "가운데") .text("중위 가족 소득 ($)")const yLabel = g.append("text") .attr("transform", "rotate(-90)") .attr("y", -40) .attr("x", -170) .attr("font-size", "20px") .attr("텍스트-앵커", "가운데") .text("기대수명(년)")const timeLabel = g.append("text") .attr("y", HEIGHT - 10) .attr("x", WIDTH - 40) .attr("font-size", "40px") .attr("불투명도", "0.4") .attr("텍스트-앵커", "가운데") .text("1980")// X 축const xAxisCall = d3.axisBottom(x) .tickValues([30000,40000,50000,60000,70000,80000]) .tickFormat(d3.format("$"));g.append("g") .attr("class", "x축") .attr("transform", `translate(0, ${HEIGHT})`) .call(xAxisCall)// Y 축const yAxisCall = d3.axisLeft(y) .tickValues([60,65,70,75,80,85,90])g.append("g") .attr("class", "y축") .call(yAxisCall)d3.json("data/current\_data.json").then(function(data){ // 데이터 정리 const formattedData = data.map(year => { return year["races"].filter(race => { const dataExists = (race.income && race.life\_exp) return dataExists }).map(race => { race.income = Number(race.income) race.life\_exp = Number(race.life\_exp) 반환 race }) }) // 0.1초마다 코드 실행 d3.interval(function(){ time = (time < formattedData.length-1) ? time + 1 : 0  update(formattedData[time]) timeLabel.text(String(time + 1980))}, 200) // 시각화 첫 번째 실행 update(formattedData[0])})함수 update(data) { // 시각화의 표준 전환 시간 const t = d3.transition() .duration(500) .ease(d3.easeLinear)  // 새 데이터와 이전 요소를 조인합니다. const circles = g.selectAll("circle") .data(data, d => d.race) // 새 데이터에 존재하지 않는 이전 요소를 EXIT합니다. circles.exit().remove() // 새 데이터에 존재하는 새 요소를 입력합니다. circles.enter().append("circle") .attr("fill", d => { if (d.race === "white") { 반환 "분홍색"; } else if (d.race === "검정") { 반환 "검정"; } else if (d.race === "all") { return "blue";}}) .merge(circles) .transition(t) .attr("cy", d => y(d.life\_exp)) .attr("cx", d => x(d.income)) .attr("r", 25) // 시간 라벨 업데이트 timeLabel.text(String(time + 1980)) }