オープンソースの冒険:エピソード29:ロシアのタンクの損失を視覚化するために古い学校のツールでD 3を使用する


まだノードがない環境がたくさんありますが、空想的なビルドシステムを持っていません.
D 3はまだこのような環境で素晴らしい作品!

D 3を得る方法


最初のステップはD 3 JavaScriptファイルをつかむことですjsdelivr - here's one for version 7 the latest . 私たちは、それにリンクするか、またはその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;
}
そして、我々の単純なapp.js D 3が機能したことを確認するには
d3.select("body").append("h1").text("Hello, World!")

タンク損失データ


さて、我々はそれを設定した今、何か面白いことをしましょう-ウクライナでロシアのタンクの損失を視覚化.We can get CSV from Kaggle .
これらはウクライナ政府からの推定であり、一般的なルールとして、歴史の誰もが敵の損失を過大評価した.
Data for which we have photographic evidence is lower . タンクのために、オリックスは425を持ちます、一方、ウクライナは676を主張します.オリックスが破壊されたロシアの装置の写真を彼らがそれを処理することができるより速く得るので、これらの数は実は非常に近いです、そして、明らかにすべての破壊されたタンクは写真を撮られるというわけではありません、そして、それが写真を撮るとしても、OLXがそれらの絵を得て、処理することの間に遅れがあります.戦いが現在停止するならば、オリックス数は刻々と過ぎ続けるでしょう.
つのファイルがあります.russia_losses_equipment.csv and russia_losses_personnel.csv , そして、最初のファイルの2つのカラムにのみ興味を持っていますdate and tank ).

データを読み込む


D 3はCSVファイルからデータを読み込むことができます.残念ながら我々は最初の小さな問題にindex.html ローカルファイルとして、ブラウザは他のファイルからデータをロードさせません.「同じ起源方針」は、「同じコンピュータの上のファイル」を意味しません.
そこで、ローカルサーバを起動する必要がありますruby -run -e httpd -- . -p 8000 またはPython等価です.
その後、我々は第2の問題に走ります.d3.csv is async , それで、次のようにします.
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スケールも時間スケールです.

データと軸の表示


現在、データ全体を表示できます.
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()
d 3デフォルトでSVG要素を生成する<0,0> ので、それを適切な場所にシフトするのは簡単ですg 適切にtransform: translate(x,y) 属性.
これは次のようになります.

今までの話


私はgithubページでこれを配備しました.
  • Hello, World
  • Tanks
  • 今度来る


    次のエピソードでは、我々はよりモダンなツールにこのアプリをポートします.その後、いくつかの近代的なフレームワークでどのように動作し、いくつかの空想の機能を追加してください.