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
- Moved the DataTable's initial
ColumnDataSourceto the global scope (namedtable_source) so the callback can modify it directly. - In the
callback, instead of creating a newColumnDataSource, we construct the new data as a dictionary and assign it totable_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
相关产品推荐
相关产品推荐

