Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Selecting Glyphs in Python Bokeh plots

Tags:

python

bokeh

I have a Python Bokeh plot containing multiple lines, Is there a way I can interactively switch some of these lines on and off?

p1.line(Time,Temp0,size=12,color=getcolor())
p1.line(Time,Temp1,size=12,color=getcolor())
p1.line(Time,Temp2,size=12,color=getcolor())
p1.line(Time,Temp3,size=12,color=getcolor())
....
show(p1)
like image 951
Paul Avatar asked Sep 29 '22 16:09

Paul


1 Answers

I just came across this problem myself in a similar scenario. In my case, I also wanted to do other operations on it.

There are 2 possible approaches:

1.) Client-server approach

2.) Client only approach


1.) Client Server Approach ak Bokeh Server

One way how you can achieve this interactivity is by using the bokeh server which you can read more about here. I will describe this way in more detail since at this point, I am a bit more familiar with it.

Going by your example above, if I were to use the bokeh serve, I would first setup a ColumnDataSource like so:

source = ColumnDataSource(data = dict(
    time = Time,
    temp0 = [],
    temp1 = [],
    temp2 = [],
    temp3 = [],
)

Next I would setup a widget that allows you to toggle what temperatures to show:

multi_select = MultiSelect(title="Option:", value=["Temp1"],
                       options=["Temp1", "Temp2", "Temp3"])
# Add an event listener on the python side.
multi_select.on_change('value', lambda attr, old, new: update())

Then I would define the update function like below. The purpose of the update function is to update the ColumnDataSource (which was previously empty) with values you want to populate in the graph now.

def update():
    """This function will syncronize the server data object with 
       your browser data object. """
    # Here I retrieve the value of selected elements from multi-select
    selection_options = multi_select.options
    selections = multi_select.value
    for option in selection_options:
        if option not in selections:
            source.data[option] = []
        else:
            # I am assuming your temperatures are in a dataframe.
            source.data[option] = df[option]

The last thing to do is to redefine how you plot your glyphs. Instead of drawing from lists, or dataframes, we will draw our data from a ColumnDataSource like so:

p1.line("time","temp0", source=source, size=12,color=getcolor())
p1.line("time","temp1", source=source, size=12,color=getcolor())
p1.line("time","temp2", source=source, size=12,color=getcolor())
p1.line(Time,Temp3, source=source, size=12,color=getcolor())

So basically by controlling the content of the ColumnDataSource which is synchronized with the browser object, I can toggle whether data points are shown or not. You may or may not need to define multiple ColumnDataSources. Try it out this way first.

2.) Client only approach ak Callbacks

The approach above uses a client-server architecture. Another possible approach would be to do this all on the front-end. This link shows how some simple interactions can be done completely on the browser side via various forms of callbacks.

Anyway, I hope this is helpful. Cheers!

like image 77
Thornhale Avatar answered Oct 07 '22 21:10

Thornhale