Plotly

簡単な例

PlotlyはJavaScriptの対話型視覚化ライブラリです。

Plotlyを使うには,<head> ... </head> の中に

<script src="https://cdn.plot.ly/plotly-2.12.1.min.js"></script>

と書き込んでおきます(あるいは上記ファイルをダウンロードして自サイトに設置し,それを上と同様に読み込みます)。

そして,グラフを入れたいところに,例えば次のような空の div を作ります。

<div id="out"></div>

その下の適当なところに,グラフを描くスクリプトを例えば次のように入れます。

<script>
  Plotly.newPlot("out", [{
    x: [1, 2, 3, 4, 5],
    y: [1, 2, 4, 8, 16]
  }], {}, {responsive: true});
</script>

すると,次のようになります。

マウスで範囲指定すると,その部分が拡大されます。軸ラベルの上でドラッグすると,グラフが平行移動します。グラフの上でダブルクリックすると,最初の状態に戻ります。グラフの上にマウスを乗せると,グラフの右上にコントロール(ボタン類)が現れます。この🏠ボタンをクリックすると,最初の状態に戻ります。

グラフの種類などはオプションで指定できます。グラフの幅はブラウザの幅になります。Plotly.newPlot() の第4引数に {responsive: true} を指定すると,レスポンシブ(ブラウザの幅に追従するデザイン)になります。小さなスマホでは幅が狭く感じられると思いますので,画面を横にしてみてください。幅と高さを明示的に設定するには,例えば次のようにします。

<div id="out" style="width: 640px; height: 480px"></div>

データの欠測値は null または NaN で表します。

背景を灰色,グリッドを白にし,ゼロ線を特別扱いしない設定:

<script>
  Plotly.newPlot("out", [{
    x: [1, 2, 3, 4, 5],
    y: [1, 2, 4, 8, 16]
  }], {
    plot_bgcolor: "#DDD",
    xaxis: {gridcolor: "white", zeroline: false},
    yaxis: {gridcolor: "white", zeroline: false}
  }, {responsive: true});
</script>

データファイルを読んでグラフを描く

データは,上の例ではHTMLファイルに直接書き込みましたが,JSONやCSVなどの形式で別にしておくほうが楽です。例えば上の例で,データを

[{
  "x": [1, 2, 3, 4, 5],
  "y": [1, 2, 4, 8, 16]
}]

のようなJSONファイルにしておけば,JavaScript部分は

fetch('test.json')
  .then(response => response.json())
  .then(data => {
    Plotly.newPlot("out", data);
  });

のようにできます。

データは同じサーバに置いておきます。JavaScriptのセキュリティ制約のため,別のサーバに置いたデータを読むことはできません。この制約をなくすためには,HTTPヘッダに Access-Control-Allow-Origin '*' を付けます(→ CORS)。GitHub(GitHub Pagesも含め)はこれが付いていますので,オープンデータとして公開したいデータはGitHubに置いておくのが楽です。Apacheで運用しているサイトなら,httpd.conf の例えば <Directory /></Directory> の中に Header set Access-Control-Allow-Origin '*' と書いておきます。

CSVファイルはJavaScriptでパースして配列にする必要があります。

Pythonのところで,平均身長の推移PythonのPlotlyで描きました。同じデータをJavaScriptだけで描いてみましょう。

このデータは height.csv というCSVファイルに収められています。欠測値は空文字列で表しています。これを読んでグラフにするために,このファイルのheadの中には,次のように書き込んであります:

<script>
function plot(data) {
  let year = [], m15 = [], m16 = [], m17 = [];
  for (const row of data.split("\n")) {
    const r = row.split(',');
    if (r.length == 27) {
      year.push(r[0]);
      m15.push(r[11]);
      m16.push(r[12]);
      m17.push(r[13]);
    }
  }
  Plotly.newPlot("out1", [
    {name: "男17歳", x: year, y: m17, type: "scatter", mode: "lines+markers"},
    {name: "男16歳", x: year, y: m16, type: "scatter", mode: "lines+markers"},
    {name: "男15歳", x: year, y: m15, type: "scatter", mode: "lines+markers"}
  ],
		 {xaxis: {title: {text: "年度"}},
		  yaxis: {title: {text: "身長"}},
		  legend: {x: 0.8, y: 0}},
		 {responsive: true});
}

window.addEventListener('DOMContentLoaded', function() {
  fetch('../python/data/height.csv')
    .then(response => response.text())
    .then(data => plot(data));
});
</script>

下の <div id="out1"></div> の中に出力されます:

CSVの仕様はけっこう難しく,JavaScriptにもCSVをパースするライブラリがいくつもあるのですが,ここでは単に改行とコンマで切り分け,中身を文字列としてそのままpushしています。この部分で数値に変換することもできますが,Number() で変換すると,空文字列が 0 に変換されてしまいます。parseFloat() なら NaN になり,Plotlyで欠測値と解釈されます。


Last modified: