使用RangeSlider在Pandas数据框中选择列以交互方式更改bokeh中的点图 [英] Interactively change a point plot in bokeh using RangeSlider to select columns in a pandas dataframe

查看:49
本文介绍了使用RangeSlider在Pandas数据框中选择列以交互方式更改bokeh中的点图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个熊猫数据框df,其中前两列代表x,y坐标,其余列代表时间片(t0,... tn),其中每个点的每个点的存在(1)或不存在(0)记录时间片(ti).

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.

我想使用 RangeSlider (而不是 Slider ),以便我可以跨一定范围的时间片滑动并绘制该范围内的绘制点.

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)

上面的代码根本不起作用.将绘制点并显示RangeSlider,但是当我更改范围或滑行时没有任何反应.我无法限制构成数据源(即数据框)的列.我尝试更改选择列的代码,但我不知道任何JavaScript.

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.

这是我第一次尝试将 CustomJS 函数用于bokeh.

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

推荐答案

上面的代码中存在许多问题:

There are a number of issues in the code above:

  • 不是 cb.obj
  • cb_obj
  • 使用现代的 js_on_change ,而不是非常老的临时 callback 参数
  • 您要分配给局部变量 data ,然后丢弃结果—需要从字面上分配给 source.data ,以确保效果.
  • 要通过更新数据源来执行此操作,您将需要两个数据源,该数据源始终具有您要从中提取的完整数据,而另一个则仅用于保存子集.如果只有一个数据源并对其进行子集化,那么现在您将丢弃永远无法取回的数据.(未来的子集将针对当前子集,而不是整个子集)
  • 因此,最好为此使用 CDSView ,它使您可以表达可更新的子集视图以应用于恒定数据源.
  • JS没有类似Pandas的操作,您只需要执行所有嵌套循环即可检查每一行以确定子集索引
  • 只是猜测,但如果您希望在滑块移动时保持相同的空间范围以进行比较,则可能需要固定x/y范围.
  • 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))

这篇关于使用RangeSlider在Pandas数据框中选择列以交互方式更改bokeh中的点图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆