Pythonによって、分析・データサイエンスされた結果は、そのままの値(生データ)羅列では分かりずらいので、グラフなどの形にして可視化して表現してやる必要があります。
Pythonには、データの可視化に特化したライブラリがいくつか用意されています。
今回の記事では、モダンで「インタラクティブ」な動的なグラフを作成することができる「Bokeh(ボケー)」を紹介します。
1. Bokehライブラリ
Pythonのグラフ作成ライブラリに「Bokeh(ボケー)」があります。(図1)
Bokehの公式サイトは次のとおりです。
Bokehの公式サイト
https://docs.bokeh.org/en/latest/index.html
本項では、Bokehの基本事項として「<1.1>ライブラリの概要」「<1.2>インストール方法」そして「<1.3>グラフ作成の手順」について順番に解説を進めます。
本サイトでの各種クラスなどの使い方は一例です。省略可能なオプション引数などについては割愛していますので、詳細や不明点などは必要に応じて公式サイトを適宜参照してください。
1.1 Bokehライブラリの概要
Bokehの特徴として「matplotlib」や「seaborn」といった静的なグラフではなく、モダンな「インタラクティブ」な動的なグラフを作成することができます。
Bokehは、BokehJSと呼ばれるJavaScriptがバックグラウンドの上で動作し、Webブラウザに動的な美しいグラフや図形を表現します。
「インタラクティブ」なグラフについてもう少し補足すると、たとえば次の図ように、マウス操作でグラフを任意の場所を拡大・縮小したり、マウスをホバーさせた個所の詳細なデータ(X, Y)の結果を表示できたりできます。
グラフにはツールボックスはついており、デフォルトでは次のような操作ができます。
上から「公式サイトを開く」「移動(Pan)」「四角形領域ズーム(BoxZoom)」「マウスホイールによるズーム(WheelZoom)」「グラフの保存(Save)」「再描画(Reset)」「ヘルプ(Help)」が並びます。
以上が、Bokehライブラリの概要説明となります。次項からはグラフ作成の手順について具体例をあげながら解説を進めます。
1.2 Bokehインストール方法
インストールは、「pipツール」もしくは「Condaコマンド」で次のようにして行います。なお、Bokehは、Anacondaディスクリプション(内部リンク)に同梱されているので、Anacondaをお使いの方は別途インストールする必要はありません。
【pipツールでインストール】
pip install bokeh
【Condaコマンドでインストール】
conda install bokeh 又は conda install -c bokeh bokeh
【バージョン確認】
bokeh info
なお、動作を保証するPython(CPython)のバージョンは3.8以上となっています。 それ以外のライブラリは次のようなバージョンのものが推奨されています。(いずれもAnacondaに同梱されています)
1.3 Bokehによるグラフ作成の手順
Bokehでグラフを作るには一定の手順(フロー)があります。本項では手順の概要を解説します。どのような複雑なグラフであっても基本的な手順はすべて同じです。
<1. プロットするデータを準備する>
プロットするためのデータを準備します。X軸、Y軸それぞれの数値もしくは、式を定義します。各データは、「リスト」でもNumpyの「ndarray (配列)」、もしくはPandasの「DataFrame」といった形式があります。csvファイルやデータセットを上記のデータ構造として取り込んで以降で扱います。
なお、Bokehではデータセットも提供していて、次のコマンドもしくはコード内でダウンロードして利用できます。
【Command】
Bokeh sampledata
【Code】
import bokeh.sampledata
bokeh.sampledata.download()
<2. Figureオブジェクトを取得する>
Bokehでは、グラフは「Figureオブジェクト」というフレームの上に描画していきます。そのため、まずはFigureオブジェクトを figure() 関数で取得することから始めます。
引数には、title(タイトル名), x_axis_label(X軸タイトル), y_axis_label(Y軸タイトル)などが指定できます。
引数指定の他にも、同オブジェクトの配下にはさまざまな「サブオブジェクト」(グラフを構成する要素)や関連するプロパティや属性があります。
<3. データをプロットする>
1.で用意したデータを、プロット(レンダラ)関数で「Figureオブジェクト」上にプロットしていきます。さまざまなグラフ種類に対応した、プロット関数がBokehには用意されています。
たとえば、プロットするマーカー(Marker)の種類には、丸(circle関数)、四角(square関数)、十字(cross関数)などがあります。(図〇)また、プロット同士をライン(線)で結ぶには「line()関数」を使用します。
各種プロット関数には、データの指定(X軸、Y軸)や凡例への表示名、色、サイズなどの指定を行うためのオプショナル引数が多数用意されています。その他、散布図、棒グラフなど…といったタイプについては公式サイトの<Gallery>を参照してみて下さい。
<4. 外観をカスタマイズする>
Figureオブジェクトの配下にはさまざまな「サブオブジェクト」(グラフを構成する要素)や関連するプロパティや属性があり、グラフの外観・見栄えをカスタマイズできます。
たとえば、
軸:軸レンジ(幅)の指定、補助線やグリッド、スケール
プロットエリア:背景色、グリッドや帯を付加する
など、個別に詳細設定できますし、テーマ(デザイン・パラメータのセット)を適用し一気に見栄えを整えることもできます。
<5. 表示または保存する>
プロットしたグラフは、show()関数で表示、save()関数 で保存ができます。それぞれの引数に対象の「Figureオブジェクト」を渡します。表示は、デフォルトではWebブラウザ上に表示されるが、出力先にJupyterNotebookのインライン表示に変更することもできる。(output_notebook()関数)
なお、表示や保存をおこなうと、グラフのHTMLファイルが自動的に生成されます。
以上が、グラフ作成の手順の概要となります。次項では具体的なグラフの作例を解説していきます。
2. グラフ作成の具体例
前項<1.3>では、Bokehでのグラフ作成の手順について解説しました。本項では、具体的にどのようにコードを記述していくのか、いつくか例を紹介していきます。
<Sample1>
まずは、基本的なグラフの作例として「プロット」「折れ線」「棒グラフ」を1枚のグラフに重ねて描画してみます。また、「凡例名」と「軸タイトル」を設定し、各プロットには色と大きさ等をそれぞれ指定しています。<List1>
from bokeh.plotting import figure, show
from bokeh.plotting import output_file
# ➀.プロットデータの準備
x = [1, 2, 3, 4, 5]
y1 = [6, 7, 2, 4, 5]
y2 = [2, 3, 4, 5, 6]
y3 = [4, 5, 5, 7, 2]
# ➁.Figureオブジェクトの生成(タイトルとX軸・Y軸のラベル名を指定
p = figure(title="Multiple glyphs example", x_axis_label="x", y_axis_label="y")
# ➂.プロット(レンダラ)関数で、データをプロットする
# 折れ線(凡例名、線色、線幅の指定)
p.line(x, y1, legend_label="Temp.", color="blue", line_width=2)
# 縦棒グラフ(凡例名、棒の幅、棒の基準(底)、色の指定)
p.vbar(x=x, top=y2, legend_label="Rate", width=0.5, bottom=0, color="red")
# 円形プロット(凡例名、色、サイズ)
p.circle(x, y3, legend_label="Objects", color="yellow", size=12)
# 保存するHTMLファイルの名前・出力先のパス
output_file("LineVbarCircle_Sample.html")
# ➃.Figureオブジェクトの表示
show(p)
それでは、<List1>の概要を説明します。
冒頭の<1,2行目>では、必要なクラス(figure)と関数(show(), output_file())をインポートします。
23行目は、出力・保存するHTMLファイルの名前と出力先を「output_file()関数」に渡します。
最後、27行目の「show()関数」で作成したFigureオブジェクトを引数に渡してWebブラウザ上に表示します。
<List1>の実行結果は、次の図〇ようになりました。このように、複数のプロットを1枚のグラフとして重ねて描画することができました。
また、同時に”LineVbarCircle_Sample.html”という名でHTMLファイルが保存されます。
<Sample.2>
次に、複数のグラフを並べて表示する例を示します。また、プロットの色をカラーマップを使ってリニア(線形)に変化させています。<List2>
from bokeh.plotting import figure, show, output_file
from bokeh.layouts import gridplot
from bokeh.transform import linear_cmap
from bokeh.palettes import Turbo256
import numpy as np
# ➀.プロットデータの準備
deg = np.arange(0, 360, 5)
rad = [np.radians(d) for d in deg] # ラジアン変換
ys1 = [np.sin(r) for r in rad] # Sin
yc1 = [np.cos(r) for r in rad] # Cos
ys2 = [np.sin(2*r) for r in rad] # Sin_角速度2倍
yc2= [np.cos(2*r) for r in rad] # Cos 角速度2倍
# ➁. カラーマップの作成
mapper = linear_cmap(field_name="y", palette=Turbo256, low=min(ys1), high=max(ys1))
# ➂.4つのFigureオブジェクトの生成とプロット関数(円プロット)の実行
# figureクラス: グラフのフレームサイズの設定 (width, plot_height)
# circle関数: プロットの大きさ, 色の設定(size, color)
# Sin
fs1 = figure(title="sin(x)", x_axis_label="x(degree)", y_axis_label="output", width=250, plot_height=250)
fs1.circle(deg, ys1, size=10, color=mapper)
# Cos
fc1 = figure(title="cos(x)", x_axis_label="x(degree)", y_axis_label="output", width=250, plot_height=250)
fc1.circle(deg, yc1, size=10, color=mapper)
# Sin 角速度2倍
fs2 = figure(title="sin(2x)", x_axis_label="x(degree)", y_axis_label="output", width=250, plot_height=150)
fs2.circle(deg, ys2, size=10, color=mapper)
# Cos 角速度2倍
fc2 = figure(title="cos(2x)", x_axis_label="x(degree)", y_axis_label="output", width=250, plot_height=150)
fc2.circle(deg, yc2, size=10, color=mapper)
# ➃. gridplot関数により、4つのFigureオブジェクトを並べる
f = gridplot([[fs1, fc1], [fs2, fc2]])
output_file("Gridplot_Sample.html")
show(f)
それでは、<List2>の概要を説明します。(<List1>と共通する点は説明を省略しています。)
<List2>の実行結果は、次の図〇ようになります。プロットの色がグラデーションする複数のグラフを並べて表示することができました。また、“Gridplot_Sample.html”というファイル名で表示・保存されます。実行結果(html)は、次からダウンロードできます。
3. Bokehその他 Tips
前節の<2.グラフ作成の具体例>では、紹介しきれなかったBokehを使う上で「知っておきたいTips」を集めました。
3.1 グラフ要素のその他設定
前節のサンプルプログラムでも既に使用していますが、Bokehにはグラフの詳細設定(カスタム)を施すための実にさまざまな属性やプロパティ・オブジェクトが提供されています。
数多あるので、そのすべてを紹介するわけにはまいりませんが、いくつか代表的なものを紹介します。
3.2 複数のグラフを同時に操作する
Bokehの面白い特徴の一つに、並べられた複数のグラフ(Figureオブジェクト)を連携させて操作(移動や拡大など)できるといったものがあります。
たとえば、先の<Sample2>のような並べられた4枚のグラフで解説すると、どれか1枚のグラフを拡大・移動すると同じ領域を共有するその他グラフもつられて動かすことができます。
単純に、オブジェクトを並べただけでは連携はできませんので、次の<List3>のように、X軸、Y軸の範囲を指定する属性( x_range, y_range )を共有する必要があります。
<List2>の37行目以降に次のコードを記述します。
4つのFigureオブジェクト(fc1,fs1,fc2,fs2)のx(y)_range属性を次の2行で共有します。
# x_range/y_range 属性でX軸、Y軸のレンジを共有する
fc1.x_range = fs1.x_range = fc2.x_range = fs2.x_range
fc1.y_range = fs1.y_range = fc2.y_range = fs2.y_range
<List3>を追加して再描画したものが、次の図8です。
4枚のグラフが連動して、移動・拡大します。
3.3 ツールチップでプロット情報を表示する
「ツールチップ」とは、カーソルをプロットにホバーすると、対象のX値、Y値をポップ表示してくれる機能のことです。
ツールチップは、「HoverTool」というクラスからオブジェクトを取得・定義してFigureオブジェクトに追加します。 追加方法は、インスタンス生成時に引数指定する場合と、後からtools属性でツールに追加することができます。<List4_1/_2>
たとえば、インスタンス時にクラスの引数指定で行う場合は、次のようにします。<List4_1>
引数:tools(9行目)に、リストの要素として「HoverToolオブジェクト」を渡し、引数:tooltips(10行目)に表示文字列を設定します。プロット値は@x, @y, @indexといったように文字列に埋め込み取得します。
from bokeh.models import HoverTool
# 途中省略
p = figure(
y_range=(0, 10),
toolbar_location=None,
tools=[HoverTool()],
tooltips="Data point @x has the value @y, index is @index",
max_width=500,
height=250
)
# 途中省略
また、tools属性にて後から追加するには、次のようにします。<List4_2>
表示するツールチップの書式をHoverToolオブジェクトで定義して、「tools.append」でリストに追加します。
from bokeh.models import HoverTool
# 途中省略
hover = HoverTools()
# 行ごとにタプル型式で書式を定義し、リストにまとめる
hover.tooltips = [
("要素", "$index"),
("座標", "$x, $y")
]
p =figure()
# Figureオブジェクトのtools属性で、ツール群(リスト形式)にツールチップを追加する
p.tools.append(hover)
# 途中省略
続く・・・