45469


# 環境

  * Python 3.6.5
  * Bokeh 0.13.0

# やりたいこと

Bokehを使ってグラフを表示しています。  
凡例をグラフ外に表示したいです。

凡例は、`line`メソッドの`legend`オプションで指定しています。

[code]

    import pandas as pd
    
    from bokeh.palettes import Spectral4
    from bokeh.plotting import figure, output_file, show
    from bokeh.sampledata.stocks import AAPL, IBM, MSFT, GOOG
    
    p = figure(plot_width=800, plot_height=250, x_axis_type="datetime")
    p.title.text = 'Click on legend entries to hide the corresponding lines'
    
    for data, name, color in zip([AAPL, IBM, MSFT, GOOG], ["AAPL", "IBM", "MSFT", "GOOG"], Spectral4):
        df = pd.DataFrame(data)
        df['date'] = pd.to_datetime(df['date'])
        p.line(df['date'], df['close'], line_width=2, color=color, alpha=0.8, legend=name)
    
    p.legend.location = "top_left"
    p.legend.click_policy="hide"
    
    output_file("interactive_legend.html", title="interactive_legend.py example")
    
    show(p)
    
[/code]

<https://bokeh.pydata.org/en/latest/docs/user_guide/interaction/legends.html>
引用

# 質問

凡例をグラフ外に表示するには、どのように記述すればよろしいでしょうか？

以下のサイトには、凡例を外に表示する方法が記載されていました。  
<https://bokeh.pydata.org/en/latest/docs/user_guide/styling.html>

[code]

    legend = Legend(items=[
        ("sin(x)"   , [r0, r1]),
        ("2*sin(x)" , [r2]),
        ("3*sin(x)" , [r3, r4]),
    ], location=(0, -30))
    
    p.add_layout(legend, 'right')
    
[/code]

しかし、今の私のコードで、`legend`オブジェクトを、どのように取得すればよいかが、分かりませんでした。


CC BY-SA 4.0
2018-07-10T01:12:53.503
45468
2018-07-10T17:47:03.827
2018-07-10T06:04:17.783
19110
19524
question
python bokeh
データ可視化ライブラリBokehで、凡例をグラフの外に表示する方法


> わざわざlegend_it.append((name, [c]))というコードを書くのは、スマートでないと感じております。
> この方法しかないのでしょうか？

スマートかどうかはわかりませんが、[bokeh/bokeh](https://github.com/bokeh/bokeh)のリポジトリを検索すると、以下のサンプルソースがありました。

[custom_tooltip.py](https://github.com/bokeh/bokeh/blob/422a437f2079290384d9a0a496379e7b492d996d/examples/plotting/file/custom_tooltip.py)

`Legend`オブジェクトの`plot`属性を`None`にすると再度、`add_layout`できるようです。

[code]

    import pandas as pd
    
    from bokeh.palettes import Spectral4
    from bokeh.plotting import figure, output_file, show
    from bokeh.sampledata.stocks import AAPL, IBM, MSFT, GOOG
    
    p = figure(plot_width=800, plot_height=250, x_axis_type="datetime")
    p.title.text = 'Click on legend entries to hide the corresponding lines'
    
    for data, name, color in zip([AAPL, IBM, MSFT, GOOG], ["AAPL", "IBM", "MSFT", "GOOG"], Spectral4):
        df = pd.DataFrame(data)
        df['date'] = pd.to_datetime(df['date'])
        p.line(df['date'], df['close'], line_width=2, color=color, alpha=0.8, legend=name)
    
    #p.legend.location = "top_left"
    p.legend.click_policy="hide"
    p.legend[0].plot = None
    p.add_layout(p.legend[0], 'right')
    
    output_file("03.html", title="interactive_legend.py example")
    
    show(p)
    
[/code]

以下、以前の回答。

本家のstackoverflowに類似の質問と回答がありました。

[Position the legend outside the plot area with
Bokeh](https://stackoverflow.com/questions/46730609/position-the-legend-
outside-the-plot-area-with-bokeh?answertab=active#tab-top)

以下のコメントに記載していますが、凡例用に値と名前の対応をlegend_itに保存してLegendを作成しています。  
凡例クリック時のmute用に`p.line`に`muted_color`,`muted_alpha`を明示的に指定する必要があるようです。

[code]

    import pandas as pd
    from bokeh.palettes import Spectral4
    from bokeh.plotting import figure, output_file, show
    from bokeh.sampledata.stocks import AAPL, IBM, MSFT, GOOG
    from bokeh.models import Legend
    
    p = figure(plot_width=800, plot_height=250, x_axis_type="datetime")
    p.title.text = 'Click on legend entries to hide the corresponding lines'
    
    legend_it = []
    
    for data, name, color in zip([AAPL, IBM, MSFT, GOOG], ["AAPL", "IBM", "MSFT", "GOOG"], Spectral4):
        df = pd.DataFrame(data)
        df['date'] = pd.to_datetime(df['date'])
    
        # 凡例の値として設定できるように変数に設定
        # mute時の色を設定
        c = p.line(df['date'], df['close'], line_width=2, color=color, alpha=0.8, muted_color=color, muted_alpha=0.2)
        # 凡例用に名前と値の対応を設定
        legend_it.append((name, [c]))
    
    # 凡例作成
    legend = Legend(items=legend_it, location=(0, 0))
    legend.click_policy="mute"
    
    p.add_layout(legend, 'right')
    
    output_file("interactive_legend2.html", title="interactive_legend.py example")
    show(p)
    
[/code]


CC BY-SA 4.0
2018-07-10T02:33:47.877
45469
2018-07-10T17:47:03.827
2018-07-10T17:47:03.827
45468
answer