ライブラリ「Bokeh」で凡例をグラフの外に描画する

2019.12.10

データアナリティクス事業本部@札幌の佐藤です。

以前、積み上げ棒グラフの実装について記載しました。

これを見ると、やはり凡例がちょっと邪魔ですよね。
若干グラフにかかってしまっているので、これをグラフの外に出したいというのが今回の話になります。

Bokehのバージョンは1.4.0です。

グラフの外に出した凡例のイメージ

こんな感じのグラフができます。

hbarcircle などに存在する legend引数ではグラフの外に出すことができないため、add_layoutを使用してグラフの外に描画させます。

実際に描画する

前回の積み上げ棒グラフの実装に追加していきます。

import pandas as pd
# bokeh系のライブラリ
from bokeh.plotting import figure, show
from bokeh.io import output_notebook
from bokeh.models import ColumnDataSource, FactorRange
from bokeh.palettes import RdYlGn

# jupyter notebookで出力させるのでoutput_notebook()を記載
output_notebook()

df = pd.read_csv("XXXX/sales.tsv", engine='python', encoding="utf-8", sep="\t", header=0)
# キャスト
df.iloc[:, [1,2,3,4]]= df.fillna("0").iloc[:, [1,2,3,4]].astype("int")

# 行列変換
dfs = df.T
# figure()に指定する用の年を設定
years = [str(i) for i in dfs.values[0]]

# X軸に表示順のListを定義
menu = ["トマトバジルチーズのスペシャルサンドイッチ", "ベリーパフェ", "チョコミントマカロン風ケーキ", "わたあめ"]

# 値を持たせた辞書型変数を定義
data = {'years' : years,
        'トマトバジルチーズのスペシャルサンドイッチ'   : dfs.values[1],
        'ベリーパフェ'   : dfs.values[2],
        'チョコミントマカロン風ケーキ'   : dfs.values[3],
        'わたあめ'   : dfs.values[4]
       }

ここまでは前回と同じです。

p = figure(y_range=years, 
           plot_width=1000,
           plot_height=500, 
           title="ペンギンカフェ年間売上高")

p.hbar_stack(stackers=menu, 
             y='years', 
             height=0.9, 
             color=RdYlGn[4], 
             source=ColumnDataSource(data=data),
             legend_label=menu)

p.xaxis.axis_label = '売上高(十万円)'   
p.add_layout(p.legend[0], "right") # 凡例をグラフの外に出す(右側)

show(p)

これだけです。
かなり簡単ですね。

ポイントとしては、expected an element of List(Instance(Renderer)), got seq with invalid items でValueErrorになるので、必ず0番目を指定してください。

ただ、このグラフ見て思いませんか?

「トマトバジルチーズのスペシャルサンドイッチ」長すぎる……。

名前を縮めたいですね。
ただ、根本のデータ自体には手を入れず、あくまで凡例だけ直したい。

凡例の文字列を変更する

Legendと、LegendItemを使用します。

from bokeh.models import Legend, LegendItem

p = figure(y_range=years, 
           plot_width=1000,
           plot_height=500, 
           title="ペンギンカフェ年間売上高")

# hbar_stackの情報を変数hbarに格納
hbar = p.hbar_stack(stackers=menu, 
                    y='years', 
                    height=0.9, 
                    color=RdYlGn[4], 
                    source=ColumnDataSource(data=data)
                    )


p.xaxis.axis_label = '売上高(十万円)'   

# 凡例を作成する
legend = Legend(items=[LegendItem(label="サンドイッチ", 
                                  renderers=[hbar[0]]),
                       LegendItem(label="ベリーパフェ", 
                                  renderers=[hbar[1]]),
                       LegendItem(label="マカロン", 
                                  renderers=[hbar[2]]),
                       LegendItem(label="わたあめ", 
                                  renderers=[hbar[3]])
                       ]
               )
p.add_layout(legend, "right")


show(p)

このように凡例の文字列が縮められました。

注意点としては、hbar変数の要素番号は積み上げ棒グラフの順番と同じなのでそれを意識するのと、 hbar_stack のlegend引数は不要という点くらいです。

最後に

凡例をグラフ外に出すという単純なことですが、意外に実装に一癖あるなというのが感想です。