You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Bokeh应用问题:点击地图点后DataTable仅显示一行数据的解决方法

Fix DataTable Showing Only One Row After Tap Event in Bokeh App

我之前也碰到过一模一样的问题,其实根源在于你更新DataTable数据源的方式不对——直接替换source对象会打破Bokeh内部的绑定逻辑,导致视图无法正确渲染所有行。咱们来快速解决它:

What's Wrong?

在你的callback函数里,你新建了一个ColumnDataSource然后直接赋值给data_table.source:

df = ColumnDataSource(data=dict(index=[50000000,55000000,60000000], LT=[13.5,20.2,-3.1]))
data_table.source = df

Bokeh的Widget和数据源是通过引用绑定的,直接替换source对象会让视图丢失对新数据源的监听,虽然数据源本身有3行数据,但视图只会渲染第一行(或者出现其他异常)。

The Fix: Update the Existing Source's data Property

正确的做法是复用初始化时创建的数据源对象,只更新它的data属性。这样Bokeh的事件系统会自动检测到数据变化,触发表格的全量刷新。

Here's the modified code:

from bokeh.plotting import figure
from bokeh.models import ColumnDataSource
from bokeh.events import Tap
from bokeh.models import TapTool, DateFormatter
from bokeh.tile_providers import get_provider, Vendors
from bokeh.models.widgets import DataTable, TableColumn
from bokeh.layouts import layout, row
from bokeh.io import curdoc

# Define the table's data source globally so the callback can access it
table_source = ColumnDataSource(data=dict(index=[0], LT=['NaN']))

def callback(event):
    """ Callback function for tap event in mapplot """
    # Update the existing source's data instead of creating a new one
    new_data = {
        "index": [50000000, 55000000, 60000000],
        "LT": [13.5, 20.2, -3.1]
    }
    table_source.data = new_data

# Map plot setup
map_source = ColumnDataSource(data=dict(x=[1196199], y=[5907860]))
tile_provider = get_provider(Vendors.CARTODBPOSITRON)
tools_to_show = 'box_zoom,pan,save,reset,tap,wheel_zoom'
p1 = figure(
    x_range=(1043319, 1471393), 
    y_range=(5684768, 6176606), 
    x_axis_type="mercator", 
    y_axis_type="mercator", 
    tools=tools_to_show, 
    sizing_mode="scale_both"
)
p1.add_tile(tile_provider)
p1.circle(x="x", y="y", size=15, fill_color="blue", fill_alpha=0.4, source=map_source)

# DataTable setup
datefmt = DateFormatter(format="%m/%d/%Y %H:%M:%S")
columns = [
    TableColumn(field="index", title="date", formatter=datefmt),
    TableColumn(field="LT", title="LT"),
]
data_table = DataTable(
    source=table_source, 
    columns=columns, 
    width=300, 
    height=600, 
    fit_columns=True, 
    editable=True
)

# Attach tap event
taptool = p1.select(type=TapTool)
p1.on_event(Tap, callback)

# Layout and run
doc_layout = layout(children=[row(p1, data_table)], sizing_mode='fixed')
curdoc().add_root(doc_layout)

Key Changes

  1. Moved the DataTable's initial ColumnDataSource to the global scope (named table_source) so the callback can modify it directly.
  2. In the callback, instead of creating a new ColumnDataSource, we construct the new data as a dictionary and assign it to table_source.data.

This way, when you tap the map point, Bokeh will detect the data change and refresh the DataTable to show all 3 rows correctly.

内容的提问来源于stack exchange,提问作者Exi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:18:47