Interactively change a point plot in bokeh using RangeSlider to select columns in a pandas dataframe

自闭症网瘾萝莉.ら 提交于 2021-02-10 20:31:40

问题


I have a pandas dataframe df where the first two columns represent x, y coordinates and the remaining columns represent time slices (t0,...tn) where the presence(1) or absence(0) of each point at each time slice (ti) is recorded.

I would like to use a RangeSlider (not a Slider) so that I can slide across a range of time slices and plot points that are present within that range.

This is what I got thus far,

from bokeh.layouts import column
from bokeh.plotting import figure, show
from bokeh.models import CustomJS, ColumnDataSource
from bokeh.models.widgets import RangeSlider

# pts is a dataframe with columns (x, y, t0, t1,...t19)
src = ColumnDataSource(data = pts) 

p = figure(plot_height = 500)
p.circle(source= src, x='x', y= 'y', size=2, color="navy", alpha=0.1)

callback = CustomJS( args = dict(source = src), code="""

    var data = source.data;
    // changed ti range
    var ti_start = cb.obj.value[0] + 2 //offset 
    var ti_end = cb.obj.value[1] + 2

    // change data (how to select columns???????) 
    data = data[ti_start:ti_end]

    source.change.emit()
""")
ti_slider = RangeSlider(start=0, end=19, value=(1,2), step=1, title="Time Period",
callback = callback)

layout = column(ti_slider, p)
show(layout)

The above code does not work at all. The points are plotted and the RangeSlider appears but when I alter the range or slide across nothing happens. I am not able to restrict the columns that make up the data source (i.e. dataframe). I have tried changing the code that selects the columns but I don't know any javascript.

This is my first time trying to use the CustomJS function with bokeh.


回答1:


There are a number of issues in the code above:

  • It is cb_obj not cb.obj
  • Use modern js_on_change, not very old ad-hoc callback parameters
  • You are assigning to a local variable data and then throwing away the result— need to literally assign to source.data at some point for there to be any effect.
  • To do this by updating data sources you would need two data sources, on that always has the complete data that you pull from, and another that you only use to hold the subset. If you only have one data source and you subset it, you've now thrown away data you can never get back. (Future subsets will be against the current subset, not the whole)
  • So, better to use CDSView for this, which lets you express an update-able subset view to apply to a constant data source.
  • JS does not have Pandas-like operations, you just have to do all the nested looping to check every row to determine the subset indices
  • Just guessing, but you will probably want to fix x/y ranges if you intend to maintain the same spatial extent for comparison, as the slider moves.

Here is a simplified working example:

from bokeh.layouts import column
from bokeh.plotting import figure, show
from bokeh.models import CustomJS, ColumnDataSource, RangeSlider, CDSView, IndexFilter

source = ColumnDataSource(data=dict(
    x=[1,2,3,4],
    y=[1,1,1,1],
    t0=[1,1,0,0],
    t1=[0,1,0,0],
    t2=[0,1,1,0],
    t3=[0,0,1,1],
    t4=[0,0,0,1],
    t5=[0,0,0,0],
))

p = figure(plot_height=500, x_range=(0,5), y_range=(0,2))

view = CDSView(source=source, filters=[IndexFilter([0, 1])])
p.circle('x', 'y', size=10, color="navy", alpha=0.8,
         source=source, view=view)

callback = CustomJS(args=dict(source=source, view=view), code="""
    const start = cb_obj.value[0]
    const end = cb_obj.value[1]
    const indices = []
    for (var i=0; i < source.get_length(); i++) {
        for (var j=start; j<=end; j++) {
            if (source.data["t" + j][i]==1) {
                indices.push(i)
                break
            }
        }
    }
    view.indices = indices
""")

ti_slider = RangeSlider(start=0, end=5, value=(0,1), step=1, title="Time Period")
ti_slider.js_on_change('value', callback)

show(column(ti_slider, p))



来源:https://stackoverflow.com/questions/58811783/interactively-change-a-point-plot-in-bokeh-using-rangeslider-to-select-columns-i

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!