识别ColumnDataSource的代码说明

问题描述 投票:0回答:2

我想根据用户从下拉菜单中选择的内容来更改简单折线图的数据源。

我有2个数据框,分别是我和男朋友的体重和年龄。

my_weight = [60,65,70] 
my_age = [21,22,25]

d_weight = [65,70,80] 
d_age = [21,22,25]

me = pd.DataFrame(list(zip(my_weight, my_age)), 
               columns =['weight', 'age'], index=None) 

dillon = pd.DataFrame(list(zip(d_weight, d_age)), 
               columns =['weight', 'height'], index=None)

我将这两个数据框转换为ColumnDataSource对象,创建我的图和线,添加我的下拉菜单和jslink。还有一个演示滑块,显示如何更改行的line_width。

from bokeh.models import ColumnDataSource
from bokeh.core.properties import Any, Bool, ColumnData

pn.extension()

source = ColumnDataSource(me, name="Me")
source2 = ColumnDataSource(dillon, name="Dillon")
# print("Me: ", source.data, "Dillon: ", source2.data)

plot = figure(width=300, height=300)
myline = plot.line(x='weight', y='age', source=source, color="pink")

width_slider = pn.widgets.FloatSlider(name='Line Width', start=0.1, end=10)
width_slider.jslink(myline.glyph, value='line_width')

dropdown2 = pn.widgets.Select(name='Data', options=[source, source2])
dropdown2.jslink(myline, value='data_source')

pn.Column(dropdown2, width_slider, plot)

当我运行此代码时,出现错误

ValueError: expected an instance of type DataSource, got ColumnDataSource(id='5489', ...) of type str

错误发生在代码的dropdown2部分。

防止代码将source和source2识别为ColumnDataSource()对象的原因是什么?got ColumnDataSource(id ='5489',...)of str类型是什么意思?字符串如何?

enter image description here

javascript python panel bokeh
2个回答
2
投票

这里有多个问题。首先是Select小部件实际上并未使复杂对象在Javascript中可用,因此试图访问JS回调中的那些模型的回调将不起作用。因此,唯一的解决方案是编写实际的JS回调并将实际模型提供为args。这里的第二个复杂之处在于,两个数据源包含不同的列,特别是“ Me” ColumnDataSource包含一个年龄列,而“ Dillon”数据源包含一个高度列。这意味着您还需要更新字形以查看这些不同的源。实际上,它看起来像这样:

import panel as pn

from bokeh.plotting import figure
from bokeh.models import ColumnDataSource, DataRange1d
from bokeh.core.properties import Any, Bool, ColumnData

source = ColumnDataSource(me, name="Me")
source2 = ColumnDataSource(dillon, name="Dillon")

plot = figure(width=300, height=300)
myline = plot.line(x='weight', y='age', source=source, color="pink")

width_slider = pn.widgets.FloatSlider(name='Line Width', start=1, end=10)
width_slider.jslink(myline.glyph, value='line_width')
dropdown2 = pn.widgets.Select(name='Data', options={'Me': source, 'Dillon': source2})

code = """
if (cb_obj.value == 'Me') {
  myline.data_source = source
  myline.glyph.y = {'field': 'age'}

} else {
  myline.data_source = source2
  myline.glyph.y = {'field': 'height'}
}
"""
dropdown2.jscallback(args={'myline': myline, 'source': source, 'source2': source2}, value=code)

话虽这么说,我建议在Panel中实施此方法的方法是:

dropdown2 = pn.widgets.Select(name='Data', options={'Me': me, 'Dillon': dillon}, value=me)
width_slider = pn.widgets.FloatSlider(name='Line Width', start=1, end=10)

@pn.depends(dropdown2)
def plot(data):
    source = ColumnDataSource(data)
    plot = figure(width=300, height=300)
    column = 'age' if 'age' in source.data else 'height'
    myline = plot.line(x='weight', y=column, source=source, color="pink")
    width_slider.jslink(myline.glyph, value='line_width')
    return plot

pn.Column(dropdown2, width_slider, plot).embed()

最后,如果您愿意尝试hvPlot,可以进一步简化为:

import hvplot.pandas

dropdown2 = pn.widgets.Select(name='Data', options={'Me': me, 'Dillon': dillon}, value=me)
width_slider = pn.widgets.FloatSlider(name='Line Width', start=1, end=10)

@pn.depends(dropdown2)
def plot(data):
    p = data.hvplot('weight', color='pink')
    width_slider.jslink(p, value='glyph.line_width')
    return p

pn.Column(dropdown2, width_slider, plot).embed()

0
投票

我不能真正地在Bokeh之上谈论Panel抽象,但是值得一提的是,实际的Bokeh滑块不能具有ColumnDataSource这样的复杂值,例如options值。只有简单的类型,例如数字,字符串等。碰巧,这是:

ColumnDataSource(id ='5489',...)

是CDS的“代表”,即,如果您尝试打印生成的字符串的CDS。因此,我的猜测是Panel在某个地方将CDS转换为其字符串表示形式,并将该字符串传递给基础的Bokeh Select部件。那当然不会做你想要的。

可能有一种更好的特定于Panel的处理方式,但是一种方法是获取基础的Bokeh Select小部件,然后调用js_on_change以添加用于更新数据的CustomJS回调。您可以在文档的JavaScript Callbacks章中模拟很多示例。

© www.soinside.com 2019 - 2024. All rights reserved.