切换散景服务 hbar 图的数据源不起作用:空白图

Switching data source for bokeh serve hbar plot not working: Blank plot

问题

我想创建一个交互式 hbar 图,您可以在其中使用 select 小部件、python 回调和本地散景服务在 3 个不同的数据源之间切换。使用默认源的绘图呈现良好,但当我切换到不同的源时,y 标签保持不变并且绘图变为空白。在 select 小部件上改回原始值不会显示我开始时使用的图并保持空白。 当我将初始源硬编码为代码中的另一个源时,它呈现得很好,直到我再次使用小部件切换它,所以数据本身似乎可以单独工作。

我错过了什么吗?我通读了许多主题、文档和教程,但没有发现我的代码有任何问题。

这是我到目前为止所做的:

我读取了一个 .csv 并创建了 3 个单独的数据帧,然后将其转换为列数据源。每个源都有 10 个数据条目,列为“物种”、“ci_lower”和“ci_upper”。 这是一个来源的示例(所有三个来源的构建方式完全相同,具有不同的分类单元 类):

df = pd.read_csv(os.path.join(os.path.dirname(__file__), "AZA_MLE_Jul2018_utf8.csv",), encoding='utf-8')

m_df = df[df["taxon_class"]=="Mammalia"]
m_df = m_df.sort_values(by="mle", ascending=False)
m_df = m_df.reset_index(drop=True)
m_df = m_df.head(10)
m_df = m_df.sort_values(by="species", ascending=False)
m_df = m_df.reset_index(drop=True)
m_source = bp.ColumnDataSource(m_df)

我在字典中保存了所有 3 个来源:

sources_dict={
    "Mammalia": m_source,
    "Aves": a_source,
    "Reptilia": r_source
}

...然后创建了名为“source”的变量,默认情况下应与“Mammalia”源交互更改:

source = sources_dict["Mammalia"]

接下来我创建了一个图形并添加了一个带有源变量的 hbar 图,如下所示:

plot = bp.figure(x_range=(0, np.amax(source.data["ci_upper"])+5), y_range=source.data["species"])

plot.hbar(y="species", right="ci_lower", left="ci_upper", height=0.5, fill_color="#b3de69", source=source)

然后我添加了带有 python 回调的 select 小部件:

def select_handler(attr, old, new):
    source.data["species"]=sources_dict[new].data["species"]
    source.data["ci_lower"]=sources_dict[new].data["ci_lower"]
    source.data["ci_upper"]=sources_dict[new].data["ci_upper"]

select = Select(title="Taxonomic Class:", value="Mammalia", options=list(sources_dict.keys()))
select.on_change("value", select_handler)
curdoc().add_root(bk.layouts.row(plot, select))

我试过这个:

我怀疑错误出在回调函数中,所以我尝试了很多不同的变体,结果都是一样的。我将在这里列出其中的一些:

我尝试使用 python 本机词典:

new_data= {
        'species': sources_dict[new].data["species"],
        'ci_lower': sources_dict[new].data["ci_lower"],
        'ci_upper': sources_dict[new].data["ci_upper"]
    }
    source.data=new_data

我尝试分配整个数据源,而不仅仅是交换数据

source=sources_dict[new]

我也试过使用 dict()

source.data = dict(species=sources_dict[new].data["species"], ci_lower=sources_dict[new].data["ci_lower"], ci_upper=sources_dict[new].data["ci_upper"])

截图

这是初始情节的屏幕截图,当我 运行 带有 bokeh serve --show file.py

的 py 文件时

这是更改 selected 值后的一个:

非常感谢任何可以帮助我解决这个问题的提示

在评论中回答您的问题,更改 data 不会更改范围,因为 y_range=some_thing 只是创建一个在幕后完成的适当范围 class 的便利。

这是您可以手动完成的方法。请注意,我根本没有触及 x_range - 默认情况下是 DataRange1d 自动计算其 start/end 值。

from bokeh.io import curdoc
from bokeh.layouts import column
from bokeh.models import Select, ColumnDataSource
from bokeh.plotting import figure

d1 = dict(x=[0, 1], y=['a', 'b'])
d2 = dict(x=[8, 9], y=['x', 'y'])
ds = ColumnDataSource(d1)


def get_factors(data):
    return sorted(set(data['y']))


p = figure(y_range=get_factors(d1))
p.circle(x='x', y='y', source=ds)

s = Select(options=['1', '2'], value='1')


def update(attr, old, new):
    if new == '1':
        ds.data = d1
    else:
        ds.data = d2
    p.y_range.factors = get_factors(ds.data)


s.on_change('value', update)

curdoc().add_root(column(p, s))