Open Source Adventures: 에피소드 29: D3를 구식 도구와 함께 사용하여 러시아 탱크 손실 시각화

18218 단어 javascriptd3
여전히 노드가 없고 멋진 빌드 시스템이 없는 많은 환경이 있으며 사용할 수 있는 것은 정적 HTML 및 JavaScript뿐입니다.

D3는 이러한 환경에서도 여전히 훌륭하게 작동합니다!

D3를 얻는 방법



따라서 첫 번째 단계는 jsdelivr - here's one for version 7 the latest 과 같은 서비스에서 D3 JavaScript 파일을 가져오는 것입니다. 링크하거나 해당 URL을 d3.js로 로컬에 저장할 수 있습니다.

간단한 정적 HTML 페이지 만들기



우리는 그것을 아주 오래된 스타일로 할 수 있습니다:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="app.css">
  </head>
  <body>
    <script src="./d3.js"></script>
    <script src="./app.js"></script>
  </body>
</html>


간단한 CSS 사용app.css:

body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}


D3가 작동하는지 확인하기 위한 간단한 app.js:

d3.select("body").append("h1").text("Hello, World!")


탱크 손실 데이터



이제 설정을 마쳤으니 흥미로운 작업을 수행해 보겠습니다. 우크라이나에서 러시아 탱크 손실을 시각화합니다. We can get CSV from Kaggle .

이것은 우크라이나 정부에서 나온 추정치이며, 일반적으로 역사상 모든 사람들은 적의 손실을 과대평가했습니다.

Data for which we have photographic evidence is lower . 탱크의 경우 Oryx는 425대, 우크라이나는 676대를 보유하고 있습니다. Oryx는 파괴된 러시아 장비의 사진을 처리할 수 있는 것보다 더 빨리 얻기 때문에 이 숫자는 실제로 매우 가깝습니다. 그것과 Oryx가 그 사진을 가져와 처리하는 것 사이에는 지연이 있습니다. 전투가 지금 중단되면 Oryx 카운트는 계속 똑딱거릴 것입니다.
russia_losses_equipment.csvrussia_losses_personnel.csv 의 두 파일이 있으며 첫 번째 파일( datetank )의 두 열에만 관심이 있습니다.

데이터 로드



D3는 CSV 파일에서 데이터를 로드할 수 있습니다. 안타깝게도 첫 번째 작은 문제가 발생했습니다. 로컬 파일index.html을 열면 브라우저에서 다른 파일의 데이터를 로드할 수 없습니다. "동일한 출처 정책"은 "동일한 컴퓨터의 파일"을 의미하지 않습니다.

따라서 ruby -run -e httpd -- . -p 8000 또는 이에 상응하는 Python으로 로컬 서버를 시작해야 합니다.

그 후 우리는 두 번째 문제에 부딪칩니다. d3.csvasync이므로 다음과 같이 하려고 합니다.

let data = await d3.csv("./russia_losses_equipment.csv")


But browsers don't support top-level await yet . 그래서 async 함수로 모두 넣어야 합니다.

CSV는 숫자와 문자열을 구분하지 않으므로 변환하는 함수를 전달할 수 있습니다.

let parseRow = ({date,tank}) => ({date: new Date(date), tank: +tank})

let main = async () => {
  let data = await d3.csv("./russia_losses_equipment.csv", parseRow)
  console.log(data)
}

main()


저울



데이터 시각화의 첫 번째 부분은 규모를 올바르게 조정하는 것입니다. d3.extent 데이터를 사용할 수 있습니다.

> d3.extent(data, row => row.tank)
[80, 676]
> d3.extent(data, row => row.date)
['2022-02-25', '2022-04-05']


하지만 80에서 손실을 시작하는 것은 어리석은 일입니다. 0에서 시작해야 합니다. 그리고 깔끔한 그래프를 위해 추가2022-02-24, 0 항목을 추가해야 할 것입니다.

이를 염두에 두고 날짜와 탱크 손실 수를 픽셀 좌표로 변환하도록 몇 가지 배율을 설정할 수 있습니다.

let parseRow = ({date,tank}) => ({date: new Date(date), tank: +tank})

let main = async () => {
  let data = await d3.csv("./russia_losses_equipment.csv", parseRow)
  data.unshift({date: new Date("2022-02-24"), tank: 0})

  let xScale = d3.scaleTime()
    .domain(d3.extent(data, d => d.date))
    .range([0, 600])

  let yScale = d3.scaleLinear()
    .domain(d3.extent(data, d => d.tank))
    .range([400, 0])
}

main()


X는 직접입니다. 오른쪽으로 이동합니다(높은 X를 향해). Y 스케일은 위로 올라갈수록 반전됩니다(낮은 Y 쪽으로). Y 척도는 시간 척도이기도 합니다.

데이터 및 축 표시



이제 전체 데이터를 표시할 수 있습니다.

let parseRow = ({date,tank}) => ({date: new Date(date), tank: +tank})

let main = async () => {
  let data = await d3.csv("./russia_losses_equipment.csv", parseRow)
  data.unshift({date: new Date("2022-02-24"), tank: 0})

  let xScale = d3.scaleTime()
    .domain(d3.extent(data, d => d.date))
    .range([0, 600])

  let yScale = d3.scaleLinear()
    .domain(d3.extent(data, d => d.tank))
    .range([400, 0])

  let svg = d3.select("body")
    .append("svg")
      .attr("width", 800)
      .attr("height", 600)
    .append("g")
      .attr("transform", "translate(100, 100)")

  svg.append("g")
    .call(d3.axisLeft(yScale))

  svg.append("g")
    .attr("transform", "translate(0, 400)")
    .call(d3.axisBottom(xScale))

  svg.append("path")
    .datum(data)
    .attr("fill", "none")
    .attr("stroke", "red")
    .attr("stroke-width", 1.5)
    .attr("d", d3.line()
      .x(d => xScale(d.date))
      .y(d => yScale(d.tank)))
}

main()


D3는 기본적으로 <0,0> 좌표에서 SVG 요소를 생성하므로 적절한 g 속성과 함께 transform: translate(x,y)로 적절한 위치로 이동하는 것이 가장 쉽습니다.

다음과 같이 표시됩니다.



지금까지의 이야기



GitHub Pages에 이것을 배포했으므로 여기에서 볼 수 있습니다.
  • Hello, World
  • Tanks

  • 다음에 온다



    다음 에피소드에서는 이 앱을 보다 현대적인 도구로 포팅할 것입니다. 그런 다음 최신 프레임워크에서 어떻게 작동하는지 살펴보고 멋진 기능을 추가합니다.

    좋은 웹페이지 즐겨찾기