3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

bokeh: すべての折れ線を非表示にする

Last updated at Posted at 2022-07-11

環境

  • Python 3.10.2
  • bokeh 2.4.3

はじめに

Pythonのbokehライブラリを使って、以下のような折れ線グラフを作りたいです。

  • グラフに10本以上の折れ線がある
  • 凡例の項目を選択すると、折れ線の表示/非表示が切り替わる。

たとえば以下の様なグラフです。

test.py
import bokeh
import numpy
from bokeh.plotting import figure, output_file, save
import bokeh.palettes

output_file("graph.html")

x_data = numpy.arange(-20, 20, 0.1)
palette = bokeh.palettes.Category10[10]

fig = figure(x_axis_label="x", y_axis_label="y")

for i in range(10):
    fig.line(x_data, numpy.sin(x_data + i), color=palette[i], legend_label=f"y=sin(x + {i})")

fig.legend.click_policy="hide"
save(fig)

image.png

やりたいこと

上記の折れ線グラフは、各折れ線が重なっていて見づらいので、注目している折れ線以外は非表示にしたいです。たとえば"y=sin(x + 5)"に注目する際は、凡例から"y=sin(x + 5)"以外の項目を選択して、注目していない折れ線を非表示にします。
しかし、折れ線の数が多いため、凡例からたくさんの項目を選択するのが面倒です。そこで、すべての折れ線を非表示にするボタンを追加することにします。

解決

bokehのButton Widgetを使って実装しました。

from bokeh.models import Button, CustomJS, GlyphRenderer

def create_button(glyph_list: list[GlyphRenderer]) -> Button:
    button = Button(label="すべての折れ線を非表示にする")

    args = {"glyph_list": glyph_list}
    code = """
        for (let glyph of glyph_list) {
            glyph.visible = false
        }
    """
    button.js_on_click(CustomJS(code=code, args=args))
    return button
    
# ~省略~
glyph_list = []
for i in range(10):
    glyph = fig.line(x_data, numpy.sin(x_data + i), color=palette[i], legend_label=f"y=sin(x + {i})")
    glyph_list.append(glyph)

fig.legend.click_policy = "hide"

button = create_button(glyph_list)
save([fig, button])

ボタンを押したときのコールバック処理では、line関数の戻り値に対してvisibleプロパティをfalseにしました。
line関数の引数visibleの説明は、以下の通りです。

Whether the glyph should be rendered.

厳密にはvisibleプロパティの説明ではありませんが、たぶん内容は同じでしょう。

すべての折れ線を非表示.gif

生成されたグラフでボタンを押すと、すべての折れ線が非表示になりました。また、凡例のすべての項目も薄い色の表示になりました。

なお、fig.legend.click_policy="mute"で、凡例の項目を選択したときに折れ線を非表示ではなくミュート(薄い色の線にする)にしている場合は、ボタンのコールバック処理内ではmutedプロパティをtrueにする必要があります。

from bokeh.models import Button, CustomJS, GlyphRenderer

def create_button(glyph_list: list[GlyphRenderer]) -> Button:
    button = Button(label="すべての折れ線をミュートにする")

    args = {"glyph_list": glyph_list}
    code = """
        for (let glyph of glyph_list) {
            glyph.muted= true
        }
    """
    button.js_on_click(CustomJS(code=code, args=args))
    return button
    
# ~省略~
glyph_list = []
for i in range(10):
    glyph = fig.line(x_data, numpy.sin(x_data + i), color=palette[i], legend_label=f"y=sin(x + {i})")
    glyph_list.append(glyph)

fig.legend.click_policy = "mute"

button = create_button(glyph_list)
save([fig, button])

すべての折れ線をミュート.gif

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?