皆さん、こんにちは!
この記事はPythonのデータ可視化ライブラリである「Bokehを学ぶシリーズ」の第3回目。
公式ドキュメントのFirst Stepを更に詳しく解説するようなイメージで進めていきます。


この記事では、第1回目ということで、Bokehとは何なのか触れつつ、公式ドキュメントのFirst Stepの1つ「Adding legends, text, and annotations」を解説していきます。
シリーズの別記事を以下にまとめておきます!
Contents
凡例の追加と細かい調整
凡例は、グラフ要素(circleやscatterなど)を定義する際に、legend_label変数を有効化することで自動的に定義されます。
以下のように、凡例の名称を定義するのみで、無難な感じで画面右上に表示されます。
p.circle(x, y3, legend_label="Objects")

ただ、これでは味気ないですし、テキストのサイズをカスタマイズしたり、フォントや色身を他のツールと揃えたいこともあるでしょう。
この時、オブジェクト(今回であれば ”p”)のlegendプロパティを用いて後からカスタマイズすることが可能です。
from bokeh.plotting import figure, show
# サンプルデータを作成
# x,yをそれぞれリスト形式
x = [1, 2, 3, 4, 5]
y1 = [4, 5, 5, 7, 2]
y2 = [2, 3, 4, 5, 6]
# 新しいプロットの作成
p = figure(title="Legend example")
# 折れ線グラフを作成する
# タイトル、軸ラベルを決定し、figureインスタンスを立ち上げる
line = p.line(x, y1, legend_label="Temp.", line_color="blue", line_width=2)
# 折れ線グラフを作成する
# タイトル、軸ラベルを決定し、figureインスタンスを立ち上げる
circle = p.circle(
x,
y2,
legend_label="Objects",
fill_color="red",
fill_alpha=0.5,
line_color="blue",
size=80,
)
### 凡例をカスタマイズする###
# 凡例の場所を左上部に調整
p.legend.location = "top_left"
# 凡例のタイトルを設定
p.legend.title = "Obervations"
# 凡例のテキストに関する部分を調整
p.legend.label_text_font = "times" # フォントを変更
p.legend.label_text_font_style = "italic" # イタリック調に変更
p.legend.label_text_color = "navy" # テキストの色を変更
# 凡例の枠線や背景色などを変更
p.legend.border_line_width = 3 # 縁線を変更
p.legend.border_line_color = "navy" # 縁線の色を変更
p.legend.border_line_alpha = 0.8 # 縁線の透明度を変更
p.legend.background_fill_color = "navy" # 凡例の背景色を変更
p.legend.background_fill_alpha = 0.2 # 凡例の透明度を変更
# 結果を描画する
show(p)
上記の例では、凡例のフォントやイタリック、色味などを変更しています。
こちらを自身でカスタマイズすることで、他のソフトと雰囲気を揃えたり、対外的に出す資料としての体裁を整えま

見出しのテキストスタイルを整える
見出しは、これまでのサンプルコードでも記述してきました。
figure関数にtitle引数を渡すことでタイトルを設定することができます。
p = figure(title="Headline example")
タイトルももちろん、フォントや色など様々カスタマイズすることが可能です。
from bokeh.plotting import figure, show
# サンプルデータを作成
# x,yをそれぞれリスト形式
x = [1, 2, 3, 4, 5]
y = [6, 7, 2, 4, 5]
# 新しいプロットの作成
p = figure(title="Headline example")
# 折れ線グラフを作成する
p.line(x, y, legend_label="Temp.", line_width=2)
# 凡例の場所を左側に移す
p.title_location = "left"
# タイトル名を変更する
p.title.text = "Changing headline text example"
# タイトルを調整する
p.title.text_font_size = "25px" # フォントを変更
p.title.align = "right" # タイトルを右に強制
p.title.background_fill_color = "darkgrey" # タイトルの背景色を変更
p.title.text_color = "white" # タイトルの文字色を変更
# 結果を描画する
show(p)

軸名を調整する(LaTeX表記、MathML表記)
Bokehでは、軸ラベルや目盛ラベルにLaTeXやMathMLといった数式を記述することも可能です。
LaTeXやMathMLは、MathJaxライブラリを使用して処理を行うため、記述方法の詳細は、MathJaxの公式ドキュメントをご確認ください。
LateX表記
LaTex表記を軸ラベルに使用する場合、MathJaxの文法(r”○○”)で記述する必要があります。
各軸の記述を変更する場合、plot.yaxis.axis_label()のように、axis_labelを用いる必要があります。
※ライブラリのインポートなどは不要です。
試しにCos関数を描画してみます。
from numpy import arange, pi, cos
from bokeh.plotting import figure, show
x = arange(-2*pi, 2*pi, 0.1)
y = cos(x)
plot = figure(height=200)
plot.circle(x, y, alpha=0.6, size=7)
plot.yaxis.axis_label = r"\[\cos(x)\]"
plot.xaxis.axis_label = r"\[x\cdot\pi\]"
show(plot)

このように各軸に数式を適用することができます。
次は軸ラベルではなく、軸に直接LaTeXを埋め込んでみます。
軸に直接埋め込みを行う場合、すこし面倒ですが文字列での記述になるため、全てユーザー側で指定してやる必要があります。
major_label_overrides関数が必要で、軸ラベルの元の値に対応したテキストを辞書型で定義します。
from numpy import arange
from bokeh.plotting import figure, show
x = arange(1, 4.5, 0.25)
y = 1 / x
plot = figure(height=200)
plot.circle(x, y, fill_color="blue", size=5)
plot.line(x, y, color="darkgrey")
plot.xaxis.axis_label = "Resistance"
# X座標の元の値に相当
plot.xaxis.ticker = [1, 2, 3, 4]
plot.yaxis.axis_label = "Current at 1 V"
# X軸をそれぞれ辞書型で定義
plot.xaxis.major_label_overrides = {
1: r"$$1\Omega$$",
2: r"$$2\Omega$$",
3: r"$$3\Omega$$",
4: r"$$4\Omega$$",
}
show(plot)

グラフ内ではなく、単純にテキストを記述したい場合もあるでしょう。
その場合は、Div関数(HTMLでいうDiv要素をBokehで操作できるもの)を用いて以下のように記述します。
もちろんLaTexにも対応しているので、数式を載せたりすることも可能です。
from bokeh.io import show
from bokeh.models import Div
div = Div(
width=400, height=100, background="#fafafa",
text="BokehでLaTexを書こう!! $$\sin^2(x) + \cos^2(x) = 1$$"
)
show(div)

グラフに注釈(Annotation)を設定する
グラフの一部分を視覚的に強調することも可能です。
このチュートリアルでは最も基本的な強調方法である、ボックスアノテーションを用います。
基本的には、「グラフのプロパティ(p = figure(○○))にアノテーションを上書きする」イメージです。
順番としては、グラフを定義した後から、アノテーションを加えます。
ボックスアノテーションでは、BoxAnnotationクラスをインポートして用います。
from bokeh.models import BoxAnnotation
以下では、グラフを3つのエリアに分けてアノテーションを作成します。
low_box = BoxAnnotation(top=20, fill_alpha=0.2, fill_color="#F0E442")
mid_box = BoxAnnotation(bottom=20, top=80, fill_alpha=0.2, fill_color="#009E73")
high_box = BoxAnnotation(bottom=80, fill_alpha=0.2, fill_color="#F0E442")
import random
from bokeh.models import BoxAnnotation
from bokeh.plotting import figure, show
# サンプルデータを作成
# xは0から50まで、yはランダムで作成
x = list(range(0, 51))
y = random.sample(range(0, 100), 51)
# 新しいプロットの作成
p = figure(title="Box annotation example")
# 折れ線グラフを作成
line = p.line(x, y, line_color="#000000", line_width=2)
# 矩形の注釈を追加
low_box = BoxAnnotation(top=20, fill_alpha=0.2, fill_color="#F0E442")
mid_box = BoxAnnotation(bottom=20, top=80, fill_alpha=0.2, fill_color="#009E73")
high_box = BoxAnnotation(bottom=80, fill_alpha=0.2, fill_color="#F0E442")
# add boxes to existing figure
p.add_layout(low_box)
p.add_layout(mid_box)
p.add_layout(high_box)
# 結果を描画する
show(p)

アノテーションは”レイアウト”の方に含まれるので、データをプロットした後に、
アノテーションを追加しても、必ず”プロット”の後ろに色を入れてくれるので、
順番を気にする必要がなく便利です。
Matplotibだと、コードの実行順にレイヤーが決まってしまうので、順番にも気を使う必要が出てしまいます。
まとめ
「Bokehを学ぶシリーズ」第3回はいかがでしたでしょうか。
まずはBokehは簡単にデータを可視化出来るだけでなく、かゆいところに手が届く非常に優秀なライブラリです。
経った数行でイイ感じのグラフを書くことが出来るBokehをマスターできれば、簡単に社内共有用のデータダッシュボードを作成することができそうです。
