如何在Bokeh表格中对行进行分组?
在Bokeh中实现表格行分组的方法
Bokeh原生的DataTable并没有直接提供现成的"行分组"UI组件,但我们可以通过自定义行样式或者改造数据源的方式,实现你截图里的分组效果,下面给你两种实用的方案:
方案一:通过背景色区分分组(简单直观)
这种方法适合快速区分不同分组的行,用不同的背景色把同一组的行归类到一起:
- 首先在你的
ColumnDataSource里新增一个group字段,用来标记每行所属的分组 - 创建
GroupedColorMapper,把不同分组映射到对应的背景色 - 用
HTMLTemplateFormatter自定义行模板,绑定颜色映射逻辑
示例代码:
from bokeh.models import ColumnDataSource, DataTable, TableColumn, GroupedColorMapper, HTMLTemplateFormatter from bokeh.plotting import show # 构造带分组标识的数据 data = { "name": ["Alice", "Bob", "Charlie", "David", "Eve"], "age": [25, 30, 35, 40, 45], "group": ["Group A", "Group A", "Group B", "Group B", "Group B"] } source = ColumnDataSource(data) # 给不同分组分配背景色 color_mapper = GroupedColorMapper( factors=["Group A", "Group B"], palette=["#f0f8ff", "#ffe4e1"] ) # 自定义行模板,根据分组字段设置背景色 row_template = """ <tr style="background-color: <%= color_mapper.lookup(group) %>"> <td><%= name %></td> <td><%= age %></td> </tr> """ row_formatter = HTMLTemplateFormatter(template=row_template, args={"color_mapper": color_mapper}) # 创建表格列与表格实例 columns = [ TableColumn(field="name", title="Name"), TableColumn(field="age", title="Age") ] data_table = DataTable( source=source, columns=columns, row_formatter=row_formatter, editable=True, selectable=True ) show(data_table)
方案二:添加分组标题行(贴近截图效果)
如果你想要像截图那样,每个分组顶部有明显的标题行,可以通过合并数据源的方式,把分组标题作为特殊行插入,再用样式区分标题行和数据行:
- 先把原始数据按分组拆分
- 为每个分组创建标题行数据,然后将标题行和对应分组的数据合并成新数据源
- 用
HTMLTemplateFormatter给标题行设置特殊样式(比如加粗、深色背景)
示例代码:
from bokeh.models import ColumnDataSource, DataTable, TableColumn, HTMLTemplateFormatter from bokeh.plotting import show # 原始分组数据 grouped_data = { "Group A": [{"name": "Alice", "age":25}, {"name": "Bob", "age":30}], "Group B": [{"name": "Charlie", "age":35}, {"name": "David", "age":40}, {"name": "Eve", "age":45}] } # 构造包含标题行的合并数据源 combined_data = {"name": [], "age": [], "is_group_title": []} for group_name, rows in grouped_data.items(): # 添加分组标题行 combined_data["name"].append(group_name) combined_data["age"].append("") combined_data["is_group_title"].append(True) # 添加分组下的数据行 for row in rows: combined_data["name"].append(row["name"]) combined_data["age"].append(row["age"]) combined_data["is_group_title"].append(False) source = ColumnDataSource(combined_data) # 自定义行模板,区分标题行与数据行 row_template = """ <tr <% if (is_group_title) { %>style="background-color: #d3d3d3; font-weight: bold;"<% } %>> <td><%= name %></td> <td><%= age %></td> </tr> """ row_formatter = HTMLTemplateFormatter(template=row_template) columns = [ TableColumn(field="name", title="Name"), TableColumn(field="age", title="Age") ] data_table = DataTable( source=source, columns=columns, row_formatter=row_formatter, selectable=True, editable=False # 禁止标题行被编辑 ) show(data_table)
小提示
- 如果你是基于Filterable Data Source示例改造,只需要把上面的行样式/数据源构造逻辑和原示例的过滤、选择逻辑结合即可
- 第二种方案里,建议把标题行设置为不可选中、不可编辑,避免用户误操作
- 你可以根据需求调整颜色、字体大小等样式,让分组效果更贴合你的设计
内容的提问来源于stack exchange,提问作者flamenco
相关产品推荐
相关产品推荐

