bokeh入門(インタラクティブなグラフ作成)

bokeh とは

インタラクティブなデータ可視化ライブラリ
(参考:bokehを使ったデータ可視化例)

作成したグラフの例

bokehのチュートリアル(First steps)のうち、必要そうな部分をまとめた。

Step 1-3. グラフの作成など

参考:Step1Step2Step3

from bokeh.io import curdoc
from bokeh.plotting import figure, show
from bokeh.models import BoxAnnotation
from bokeh.models.tools import HoverTool

#データを準備する
x = [1, 2, 3, 4, 5]
y1 = [6, 7, 2, 4, 5]
y2 = [2, 3, 4, 5, 6]
y3 = [4, 5, 5, 7, 2]

# オブジェクトを作成
p = figure(title="Multiple glyphs example",x_axis_label="x", y_axis_label="y")

# 複数のグラフを描画する
line = p.line(x, y1, legend_label="Temp.", line_color="blue", line_width=2)
circle = p.circle(x, y3, legend_label="Objects", line_color="yellow", size=12)
# vbar = p.vbar(x=x, top=y2, legend_label="Rate", width=0.5, bottom=0, color="red")

# 判例を追加する
p.legend.location = "top_left"

#塗りつぶし
box = BoxAnnotation(bottom=2, top=4, left=1,right=3,fill_alpha=0.1, fill_color="red")
p.add_layout(box)

# 一度作成したグラフのプロパティを変更することも可能(散布図の塗りつぶしを青に変更してみる)
glyph = circle.glyph
glyph.fill_color = "blue"

# グラフを表示する
show(p)

Step 4. グラフをカスタマイズする

参考:step4

グラフテーマの変更

(参考:グラフテーマ一覧

from bokeh.io import curdoc
from bokeh.plotting import figure, show

x = [1, 2, 3, 4, 5]
y = [4, 5, 5, 7, 2]

# グラフのテーマを変える。
# curdoc().theme = 'caliber'
curdoc().theme = "dark_minimal"

p = figure(sizing_mode="stretch_width", max_width=500, plot_height=250)
p.line(x, y)

show(p)

ツールの追加

from bokeh.models.tools import BoxZoomTool, PanTool, ResetTool
from bokeh.plotting import figure, show

# prepare some data
x = [1, 2, 3, 4, 5]
y = [4, 5, 5, 7, 2]

# create a plot
p = figure(
    title="Modifying tools example",
    tools=[BoxZoomTool(), ResetTool()],
    sizing_mode="stretch_width",
    max_width=500,
    plot_height=250,
)

# ツールを追加する
p.add_tools(PanTool(dimensions="width"))

#toolbarの位置の変更
p.toolbar_location = "right"
# p.toolbar_location = None #非表示にしたい時
# p.toolbar.autohide = True #自動的に非表示にするかどうか。

# add a renderer
p.circle(x, y, size=10)

# show the results
show(p)

HoverToolを使う

マウスが特定のポイントに来た時に情報を表示する。
"@"を使用して、表示させたいデータのソース名を定義できる。

from bokeh.models.tools import HoverTool
from bokeh.plotting import figure, show

# prepare some data
x = [1, 2, 3, 4, 5]
y = [4, 5, 5, 7, 2]

p = figure(
    y_range=(0, 10),
    toolbar_location="right",
    tools=[HoverTool()],
    tooltips="Data point @x has the value @y",
    sizing_mode="stretch_width",
    max_width=500,
    plot_height=250,
)

p.circle(x, y, size=10)
p.line(x, y, line_width=2)

show(p)

Step 5. グラフプロパティのベクトル化

データの値の大きさをグラフの色や大きさなどの性質に反映させる。
参考:step5

プロパティのリストを作成する方法

import numpy as np
from bokeh.plotting import figure, show

N = 1000
x = np.random.random(size=N) * 100
y = np.random.random(size=N) * 100

# yの大きさに応じた円の半径のリストを作成する。
radii = y / 100 * 2

# yの大きさに応じた色のリスト(rgb hex colors で表現)を作成する。
colors = ["#%02x%02x%02x" % (255, int(round(value * 255 / 100)), 255) for value in y]

# グラフ作成
p = figure(
    title="Vectorized colors and radii example",
    sizing_mode="stretch_width",
    max_width=500,
    plot_height=250,
    )

# 散布図を作成(作成した、半径、色のリストを指定)
p.circle(
    x,
    y,
    radius=radii,
    fill_color=colors,
    fill_alpha=0.6,
    line_color="lightgrey",
    )

show(p)

パレットを使用したカラーマッピング

Bokehには、あらかじめ定義された数多くのカラーパレットが用意されており、これを使ってデータに色をマッピングすることがでできる。
カラーパレット一覧

from bokeh.io import show
from bokeh.palettes import Turbo256
from bokeh.plotting import figure
from bokeh.transform import linear_cmap

x = list(range(-32, 33))
y = [i**2 for i in x]

# カラーマップを作成する。(使用するパレットや、データの最小・最大値を指定)
mapper = linear_cmap(field_name="y", palette=Turbo256, low=min(y), high=max(y))

# グラフを作成
p = figure(plot_width=500, plot_height=250)

# 散布図を作成し、colorに先ほど作成したカラーマップを指定する。
p.circle(x, y, color=mapper, size=10)

show(p)

Step 6. 複数プロットの描画

layoutメソッドやrowメソッド, gridplotメソッドを使う
参考:step6

from bokeh.layouts import row, layout, gridplot
from bokeh.plotting import figure, show

# prepare some data
x = list(range(11))
y0 = x
y1 = [10 - i for i in x]
y2 = [abs(i - 5) for i in x]

# create three plots with one renderer each
s1 = figure(plot_width=250, plot_height=250, background_fill_color="#fafafa")
s1.circle(x, y0, size=12, color="#53777a", alpha=0.8)

s2 = figure(plot_width=250, plot_height=250, background_fill_color="#fafafa")
s2.triangle(x, y1, size=12, color="#c02942", alpha=0.8)

s3 = figure(plot_width=250, plot_height=250, background_fill_color="#fafafa")
s3.square(x, y2, size=12, color="#d95b43", alpha=0.8)

s4 = figure(plot_width=250, plot_height=250, background_fill_color="#fafafa")
s4.square(x, y0, size=12, color="#d95b43", alpha=0.8)

# layoutメソッドを使う
show(layout([[s1, s2], [s3, s4]]))

# rowメソッドを使う
# show(row(s1, s2, s3))

# gridplotメソッド
# show(gridplot([[s1, s2],[s3, s4]]))

Step 7. 表示や出力

参考:step7

HTMLファイルに出力する

from bokeh.plotting import figure, output_file, save

x = [1, 2, 3, 4, 5]
y = [4, 5, 5, 7, 2]

# HTMLファイルに出力する場合
output_file(filename="custom_filename.html", title="Static HTML file")

p = figure(sizing_mode="stretch_width", max_width=500, plot_height=250)
circle = p.circle(x, y, fill_color="red", size=15)

# 結果をファイルに保存する
save(p)

Jupyter notebook上で表示する

output_notebook() を記載する。

from bokeh.plotting import figure, output_notebook

x = [1, 2, 3, 4, 5]
y = [4, 5, 5, 7, 2]

# HTMLファイルに出力する場合
output_notebook()

p = figure(sizing_mode="stretch_width", max_width=500, plot_height=250)
circle = p.circle(x, y, fill_color="red", size=15)

# 結果をJupyter Notebook上で表示する
show(p)

Step 8. データのフィルタリング

データにフィルターをかけて、特定のデータのみ表示できるようにする。
Bokeh独自のデータ構造(ColumnsDataSource)を経由して、データを描画する。
参考:Step8

from bokeh.layouts import gridplot
from bokeh.models import CDSView, ColumnDataSource, IndexFilter
from bokeh.plotting import figure, show

# 辞書からColumnDataSourceを作成する
source = ColumnDataSource(data=dict(x=[1, 2, 3, 4, 5], y=[1, 2, 3, 4, 5]))

#pandas dataFrameからColumnDataSourceを作成することも可能
# source = ColumnDataSource(df)

# インデックスでフィルターをかけた、データ(view)を作成
#(create a view using an IndexFilter with the index positions [0, 2, 4])
view = CDSView(source=source, filters=[IndexFilter([0, 2, 4])])

# 全てのデータを使ってプロット
p = figure(plot_height=300, plot_width=300)
p.circle(x="x", y="y", size=10, hover_color="red", source=source)

# フィルターをかけた特定のデータを使ってプロット(viewに先ほどのviewを渡す)
p_filtered = figure(plot_height=300, plot_width=300)
p_filtered.circle(x="x", y="y", size=10, hover_color="red", source=source, view=view)

show(gridplot([[p, p_filtered]]))

Step 9. ウィジェット(widget)の使用

プロットにインタラクティブなウィジェットを追加する。
グラフを操作して、描画する範囲やデータ、グラフのプロパティなどを動的に変化させることができる。
参考:step9

from bokeh.layouts import layout
from bokeh.models import Div, RangeSlider, Spinner
from bokeh.plotting import figure, show

x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
y = [4, 5, 5, 7, 2, 6, 4, 9, 1, 3]

# グラフ作成
p = figure(x_range=(1, 9), plot_width=500, plot_height=250)
points = p.circle(x=x, y=y, size=30, fill_color="#21a7df")

# テキストエリアとテキスト(HTML形式)を作成する(ウィジェットの説明用)
div = Div(
    text="""
          <p>Select the circle's size using this control element:</p>
          """,
    width=200,
    height=30,
        )

# spinner(数字を選択するウィジェット)
spinner = Spinner(title="Circle size",
                    low=0,
                    high=60,
                    step=5,
                    value=points.glyph.size, #初期値
                    width=200,
                    )

# スピナーによって生成された値をグリフのsizeプロパティにリンクさせるには、js_link()関数を使用する。
# この関数に渡す最初の引数は、
spinner.js_link("value", #円のglyphにリンクさせたいspinnerの属性(「value」)
                points.glyph, # spinnerにリンクさせたいglyph(points.glyph)です。
                "size" # spinnerの値にリンクさせたいglyphのプロパティです。
               )

# RangeSlider(スライダーで範囲を選択するウィジェット)
# spinner と同様にオブジェクトを作成し、js_linkでつなぐ。
range_slider = RangeSlider(
                title="Adjust x-axis range",
                start=0,
                end=10,
                step=1,
                value=(p.x_range.start, p.x_range.end),
                )
range_slider.js_link("value", p.x_range, "start", attr_selector=0)
range_slider.js_link("value", p.x_range, "end", attr_selector=1)

# テキストエリア、ウィジェット、グラフのレイアウトを決める
layout = layout([
                [div, spinner],
                [range_slider],
                [p],
                ])

show(layout)

参考

参考書籍