見出し画像

さわってみよう、D3.js(前編)

はじめに

先日、グラフを作成する技術のひとつである「D3.js」というものの紹介記事を書きました。

例によってごちゃごちゃ書いてますが、申し上げたかったのは以下の3点です。

  1. Baseball Savant等のサイトでも使われている技術(JavaScriptのライブラリ)

  2. 高度なグラフを作成することができるもの

  3. ただし、くそほど面倒

前回の記事では「こんなものだよ」の紹介にとどめたかったこともあり、概要に触れたのみで、どのように書くか(つまりコードの中身)については踏み込みませんでした。

なのですが、改めて読み返してみたところ「これじゃどんなもんだかわかりゃしねえ」との感想を持つに至ったため、今回はあえてグラフを作ってみます。

とてつもなく簡単なグラフをサンプルにD3.jsの実例をお示しすることで、D3.jsとはどんなものか、またどれだけ面倒なのかをご紹介したく考えております。


概要

目的

以下の2点とします。

  • D3.jsでかんたんなグラフを(とにかく)作ってみる。

  • 作り方のお作法をご紹介する。

アウトプットイメージ

今回は「とにかくD3.jsでグラフを作ってみる」ことが目的です。何度も何度も言っていますが、「くそほど面倒」というのがどれほどかを示すため、アウトプットについては極力かんたんなものとします。

なお、今回のアウトプットは2023年度のセントラル・リーグにおける本塁打トップ3を棒グラフにしたものです。Excelの場合、以下の画像のような感じになります。

Excelなら1分くらいでできます

これがD3.jsで作成した場合どうなるかは、以降の項でご紹介します。

つくるもの

D3.jsは「JavaScript」というプログラムのため、表示させるための場としてHTMLファイルが必要です。普段よく見るWebサイトと同じ理屈です。
そのため、今回はHTMLファイル、JavaScriptファイルの2つを作成します。

少しWeb関連の知識をご存知の方であれば、「スタイルシート(CSS)は?」との疑問をお持ちになるかと思いますが、今回は至極かんたんなもののため、スタイリングはHTMLの中で行うこととします。

あるとよい知識

D3.jsはJavaScriptのライブラリです。ですので、言うまでもなくJavaScriptの知識があると非常に理解がしやすいです。

しかし、弊アカウントの記事は主に野球のことが主題であり、技術に特化したものではありません。ですので、おそらく読者の方がいるとすれば、野球には興味があるけれど技術はあまり、という方が多いのではないかと愚考しております。

私自身とてエンジニアでもないただの会社員なため、この取り組み自体が無謀ではあるのですが、そのようなないない尽くしの中で挙げられるものがあるとすれば、以下のような知識がほんの少しでもあれば違うのではないかと思います。

  • なにかしらのプログラミング経験(Java、Python、C等。なんでもいいです)

  • Web周りの知識(HTML、CSS)

  • データベースの知識

今回のコードはコピペすればグラフを表示できるようにしてありますので、全く知識がない方でも極力イメージをつかみやすいようにしたいと考えておりますが、なにぶんテーマがテーマのため、限界があることをご承知おきいただけますと幸いです。

やってみよう

能書きを垂れてばかりでもしょうがないので、コードを先に示します。

HTML (index.html)

<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <title>2023年 セ・リーグ本塁打3傑</title>
    <script src="https://d3js.org/d3.v7.min.js"></script>
    <script src="script.js" defer></script>
    <style>
        .bar {
            fill: steelblue;
        }
        .bar:hover {
            fill: orange;
        }
        .axis-label {
            font-size: 12px;
        }
        .axis--x text {
            font-size: 14px;
        }
    </style>
</head>

<body>
    <h1>ホームラン数の棒グラフ</h1>
    <svg width="600" height="400"></svg>
</body>
</html>

JavaScript (script.js)

// データの準備
const data = [
    { "name": "岡本", "homerun": 41 },
    { "name": "村上", "homerun": 31 },
    { "name": "牧", "homerun": 29 }
];

// SVG要素の設定
const svg = d3.select("svg"),
    margin = { top: 20, right: 30, bottom: 50, left: 40 },
    width = +svg.attr("width") - margin.left - margin.right,
    height = +svg.attr("height") - margin.top - margin.bottom,
    g = svg.append("g").attr("transform", `translate(${margin.left},${margin.top})`);

// x軸とy軸のスケールを設定
const x = d3.scaleBand()
    .domain(data.map(d => d.name))
    .range([0, width])
    .padding(0.1);

const y = d3.scaleLinear()
    .domain([0, d3.max(data, d => d.homerun)])
    .nice()
    .range([height, 0]);

// x軸とy軸をSVGに追加
g.append("g")
    .attr("class", "axis axis--x")
    .attr("transform", `translate(0,${height})`)
    .call(d3.axisBottom(x))
    .append("text")
    .attr("class", "axis-label")
    .attr("x", width / 2)
    .attr("y", margin.bottom - 10)
    .attr("fill", "#000")
    .text("選手名");

g.append("g")
    .attr("class", "axis axis--y")
    .call(d3.axisLeft(y).ticks(10))
    .append("text")
    .attr("class", "axis-label")
    .attr("x", -margin.left)
    .attr("y", -10)
    .attr("fill", "#000")
    .attr("text-anchor", "start")
    .text("ホームラン数");

// 棒グラフを描画
g.selectAll(".bar")
    .data(data)
    .enter().append("rect")
    .attr("class", "bar")
    .attr("x", d => x(d.name))
    .attr("y", d => y(d.homerun))
    .attr("width", x.bandwidth())
    .attr("height", d => height - y(d.homerun));

作成イメージ

棒にカーソルを重ねると色が変わります

よほど慣れている人でもない限り、これを見せられたら「なげえよクソが」と思うのが普通ではないでしょうか。自分もそうです。ですが、これがD3.jsなのです。

HTML、JavaScriptの双方で装飾のためにいくつかコードを足してはいますが、ほぼ最小限の構成でもこのようなコードを書かなくてはなりません。

これらのファイルを同じフォルダ内に置き、HTMLファイルをブラウザにドラッグすれば表示されるはずです(動作確認済。フォルダ構成を変えたい場合はファイルパスを修正してください)。もしよろしければ一度お試しくださいませ。

なお、次項以降ではもしかしたらいるかもしれないご興味を持ってくださった方のために、ソース内部のポイントについて逐次解説してみます。が、なにぶん書いている人間が大概素人なため、内容に抜け・漏れ・不備があることはご容赦ください。

解説:HTML

今回のサンプルで作成するHTML、JavaScriptのうち、前者について説明します。
HTMLのソースをご覧になった方ならばわかるかもしれませんが、ほとんど初期構成のままです。ただし3点ほど修正している点があるので、それらについて詳述します。

修正点1:D3.jsの呼び出し

以下の部分でライブラリであるD3.jsを呼び出しています。D3にはいくつかのバージョンがあるのですが、今回はv7(2024年5月時点での最新)を指定しています。

<script src="https://d3js.org/d3.v7.min.js"></script>

ライブラリのファイル自体をダウンロードすることもできます。本格的に開発する場合はその方が良いかもしれませんが、今回はサンプルということもあり、上記の1行コードだけで済ませています。

修正点2:スタイルの指定

このHTMLでは、ファイル内部で特定箇所のスタイリング(色や文字の指定)を行っています。具体的には以下の箇所です。

    <style>
        .bar {
            fill: steelblue;
        }
        .bar:hover {
            fill: orange;
        }
        .axis-label {
            font-size: 12px;
        }
        .axis--x text {
            font-size: 14px;
        }
    </style>

ここの記述は「スタイルシート」に該当する部分です。今回は指定箇所が少ないのでHTML内に書いてしまっていますが、通常こんなものでは済みません。そのため、本来はCSSファイルとして分けるのが一般的かと思います。

CSSをご存知の方には釈迦に説法ですが、ここで「.bar」といった具合に先頭にドット(ピリオド)がついている文字列を「クラス」と呼びます。今回はそのクラスを4つ指定しています。
ここである程度知識のある方の中には、「HTMLでクラスを設定していないのに、CSSで対象となるクラスを指定していないのはなぜか」という疑問が浮かんだ方いるかもしれません。答えは簡単、D3で指定しているからです。これについては後述します。

なお、指定内容は「fill」と「font-size」の2種のみです。前者は塗りの色を、後者は文字のサイズを指定しています。

修正内容3:描画領域(SVG)の設定

D3のグラフはSVGで描画されます。以下の部分で「SVGを書くよ」と指定しています。

<svg width="600" height="400"></svg>

SVGとは「Scalable Vector Graphics」の略で、いわゆるベクター画像と呼ばれるものです。通常の画像(jpgやpng等)が画像の拡大・縮小で画質が劣化するのに対し、SVGは画像を拡大縮小しても劣化しないため、自由にカスタマイズすることが可能です。

D3の場合、グラフのサイズをピクセル単位で指定することが一般的ですが、往々にしてサイズを変えることがあります。SVGであることで、こうした変更があっても見た目を一定に保ってくれる効用があります。

なお、今回のサンプルでは作成するグラフ(SVG画像)が1つであるため、svgタグ1つを書くだけで対応しています。HTML上に複数のグラフを作成したい場合は、HTML側に一意のIDをつけることが必要になると思います。

ちなみに、グラフの作成先としてsvg以外のタグ(div等)を指定することも可能です。「HTMLのどこにグラフを表示させるか」はJavaScript側で制御することとなります。

つづき

毎回D3.jsでグラフを書くたび、コードの長さに辟易しているのですが、ここまで書いてきた文字数を確認するとすでに5,000字を超えており、辟易すべきはD3ではなくむしろ自分の無能力なんじゃないかという気がしてきました。

この次に控えるのはその妙に長ったらしいコードの解説なのですが、初心者ふぜいの稚拙な説明能力では、どう考えてもここまでと同じくらいの分量になりそうなので、本記事はいったん以上とし、D3(JavaScript)は後編で解説します。
引っ張るようですみません。くっそ長くてすみません。

最後に、こんなザ・初心者のサンプルグラフでは伝えられそうもないD3の素晴らしさについて、海外のすてきなサンプル集をご紹介することで代えさせていただきたいと思います。すごいんすよ、ほんとに。


この記事が気に入ったらサポートをしてみませんか?