はじめに
jupyter notebookでpythonだけでもデータ解析から可視化まで一連の流れが可能ですが、D3.jsの高い表現力とインタラクティブ性をみてしまうと、可視化はJavaScriptでというケースも多くなるのではないでしょうか。そこで、データはpythonで用意してJavaScriptに引き渡す方法を紹介したいと思います。
以下の説明ではpy_d3というjupyter notebook上でD3.jsのコードを実行、表示するパッケージを利用しますが、D3.jsに限らず任意のJavaScriptが実行可能です。1
py_d3のセットアップ
pip install py_d3
でインストールできます。機能を利用するにはnotebookの先頭などで以下のように記述します。
%load_ext py_d3
その上でセルの先頭で %%d3
と記述するとそのセル中のコードはHTMLとJavaScriptとして解釈されます。
前準備
連携はIPython.display.HTMLパッケージの機能を使いますがそのままでは使いにくいので、以下のJavaScriptの関数を定義してラッピングして使うことにします。%load_ext py_d3
の直後のセルなどで実行してください。snippetsなどに登録しておくのがいいです。
%%d3
<script>
function pyexec(command) {
return new Promise(res => {
IPython.notebook.kernel.execute(command,
{iopub: {
output:
out => res(JSON.parse(eval(out.content.data["text/plain"])))
}},
{silent: false});
});
}
</script>
連携
実行するpythonのコードを文字列にして上記のpyexec関数に渡します。python側ではjson形式で値をもどすようにしてください。
たとえばpython側で以下のように関数を定義しておきます。
import json
import numpy as np
def get_data(count):
return json.dumps((np.random.rand(count)*10).tolist())
JavaScript側は以下のように記述します。pyexecのあとのthenの中でデータを受け取ってから行う処理を記述します。今回はD3.jsのチュートリアルにのっていたシンプルなサンプルを実行しています。
%%d3
<g></g>
<style>
element {
height: 25px;
}
div.bar {
display: inline-block;
width: 20px;
height: 75px;
margin-right: 2px;
background-color: teal;
}
</style>
<script>
pyexec("get_data(7)")
.then(dataset => {
d3.select("g").selectAll("div")
.data(dataset)
.enter()
.append("div")
.attr("class", "bar")
.style("height", function(d) {
let barHeight = d * 5;
return barHeight + "px";
});
});
</script>
すると以下のようなグラフがnotebook上に描画されます。
今回作成したnotebookを公開しておきます→ http://nbviewer.jupyter.org/gist/ssugiyama/29b586b25dc63730eb67ee6c1daefac8