プロジェクトワークの合間に、Bokehというライブラリを使って、JavaScriptをさほど書かずにウェブネイティブのアニメーションチャートを作成してみました。

こちらからアニメーションの操作が可能 —> https://www.wis-dam.com/showcase/gafam-marketcap

Bokehとは?

Bokehは、インタラクティブなウェブチャート(グラフ)を作成するPytohnのライブラリーです。綺麗なグラフィックを作れて、シンプルなチャートから複雑なダッシュボードまで作成可能です。Bokehを使えば、JavaScriptによる高度な可視化機能をJavaScriptのコードをほとんど書かずに使うことができます。(Bokehオフィシャルサイトより翻訳)

他のPython可視化ライブラリーとどう違うか

Pythonには、他にも優れた可視化ラブラリーがたくさんあります。有名どころでは、Matplotlib, Seaborn,Plotlyなどです。Bokehを使う一番のメリットは、ウェブページやアプリとの親和性の高さかと思います。簡単にウェブネイティブな可視化のコンテンツを作成し、あらゆるウェブページやアプリに挿入することができます。

もし、ただnotebook内でデータを可視化したい場合などは、Bokehを使うメリットはさほど無いでしょう。

GAFAMの時価総額レース

今回は、https://companiesmarketcap.com/のサイトで日々更新されているデータをもとに、GAFAM (Google, Amazon, Facebook, Apple, Microsoft)の2015年以降の時価総額の推移を比較するウェブチャートを作成しました。

Import libraries

ライブラリーは、Bokehの中から色々とimpotする必要があります。特に、widgetを入れたり、フォーマット(色、軸の書式など)をカスタマイズしたい場合、多くのコンポーネントを使います。

from bokeh import events
from bokeh.plotting import figure, show,save,gridplot
from bokeh.models import ColumnDataSource, NumeralTickFormatter,HoverTool,Range1d,CustomJS,DateSlider,Button,CrosshairTool
from bokeh.layouts import layout
from bokeh.embed import components

Prepare Dataframe

今回データの準備は飛ばします。ライブページでは、バックエンドでスクレーピングした結果を日々取得しています。

使っているデータは以下のようなものです。

timeのコラムは、Unixのタイムスタンプで、他の会社名のコラムは時価総額の値が入っています。

データを用意したら、ColumnDataSource()を使って、Bokehにデータを渡します。

source = ColumnDataSource(df)

チャートを書く

Bokehにデータを渡したら、シンプルなコードでチャートを作成できます。下のコードでは、5社分のデータがあるので、5つのライングラフを書いています。

p = figure(height=600,width=1200,
           x_axis_type='datetime',
           y_axis_label='',
           title='GAFAM Market Cap Race since 2015'
          )p.line(x='time',y='Apple',source=source,color='black',line_width=1.5)
p.line(x='time',y='Amazon',source=source,color='#f59400',line_width=1.5)
p.line(x='time',y='Alphabet',source=source,color='#4081ec',line_width=1.5)
p.line(x='time',y='Microsoft',source=source,color='#ea4e21',line_width=1.5)
p.line(x='time',y='Meta',source=source,color='#00c6f7',line_width=1.5)

アニメーションを追加する

続いて、アニメーションを追加します。Widget(ボタンやスライダー)を追加し、コールバックを設定します。Bokehでは、①pythonコードのみによるコールバックの設定、②カスタムJSコールバックを設定するか、の2つの方法がありますが、ウェブサイトやアプリへ簡単に挿入するためには、②の方法に依る必要があります。

まず、widgetを作成します。

button = Button(label='► Play', width=60)
slider = DateSlider(value=initial_ts,start=initial_ts,end=df.time[len(df)-1],
                    format="%Y-%m",step=31*24*60*60*1000)

そして、データなどの変数をJavaScriptへ渡しながら、コールバックを設定し、widgetに紐付けます。

button_js = CustomJS(args={'source': source, 'data': data,'slider':slider,'button':button,'initial_sv':initial_ts}, code="""
const step = 31*24*60*60*1000;
const getNewData = (sliderValue) => {
    let newData = {};
    const newLength = data.time.filter(t => t <= sliderValue).length
    Object.keys(data).forEach(key => newData[key] = data[key].slice(0,newLength));
    return newData
}const updateChart = (sliderValue) => {
    if( sliderValue > data.time[data.time.length-1] ){
        clearInterval(button.id);
    } else {
        source.data = getNewData(sliderValue)
        slider.value = sliderValue + step
    }
}if(button.label == '► Play'){
    if( slider.value >= data.time[data.time.length-1] ){
        slider.value = initial_sv;
    }
    button.label = '❚❚ Pause';
    button.id = setInterval(function(){updateChart(slider.value)}, 200)
} else {
    button.label = '► Play';
    clearInterval(button.id);
};""")

button.js_on_event(events.ButtonClick, button_js)

チャートのエクスポート

最後にチャートをエクスポートします。スタンドアローンのHTMLとしてアウトプットすることで、あらゆるウェブ上で使うことができます。

layout = layout([
    [p],
    [slider, button],
], sizing_mode='scale_width')

script, div = components(layout)

script変数の中身:

div変数の中身:

上記コードを使ったチャートはこちらから確認できます。

Posted by: Ryoichi Fujita(藤田亮一)