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

如何用Bokeh创建适配可变Excel输入输出的动态堆叠柱状图

动态适配数据结构的Bokeh堆叠柱状图解决方案

我正在开展一项数据可视化项目,需使用Bokeh创建堆叠柱状图。数据来自定期更新的Excel文件,包含数量可变的输入与输出字段,数据结构会发生变化。目标是让Bokeh图表无需手动修改代码,即可自动适配这些变化,能展示固定部分输入、其余输入可变时对应的所有输出堆叠情况。目前已实现固定2个输入、3个输出场景的静态堆叠图,但无法找到适配输入输出数量动态变化的解决方案,希望获得可自动读取Excel、识别数据结构并更新图表的方案。


示例数据结构

Input_1Input_2Output_1Output_2Output_3
11100200200
21150150200
31200100200
12200200100
22150200150
32100200200
13200100200
23200150150
33200200100

静态场景实现代码

import pandas as pd
from bokeh.plotting import figure, output_file, show
from bokeh.layouts import gridplot, row
from bokeh.models import ColumnDataSource


data_frame = pd.read_excel("example.xlsx")

data_frame['Input_1'] = data_frame['Input_1'].astype(str)
data_frame['Input_2'] = data_frame['Input_2'].astype(str)

output_file("stacked_bar_charts.html")

unique_input_1 = data_frame['Input_1'].unique()
unique_input_2 = data_frame['Input_2'].unique()

plots_for_input_1 = []
plots_for_input_2 = []


for value in unique_input_1:

    filtered_data = data_frame[data_frame["Input_1"] == value]
    filtered_data = filtered_data.sort_values(by='Input_2')

    source = ColumnDataSource(filtered_data)

    plot = figure(title=f"Input_1 = {value} fixed",
                  x_range=filtered_data["Input_2"].unique(),
                  height=300,
                  width=500
                  )

    plot.xaxis.axis_label = "Input_2"

    plot.vbar_stack(stackers=["Output_1", "Output_2", "Output_3"],
                    x="Input_2",
                    width=0.9,
                    color=["orange", "gray", "brown"],
                    source=source,
                    legend_label=["Output 1", "Output 2", "Output 3"]
                    )

    plots_for_input_1.append(plot)


for value in unique_input_2:

    filtered_data = data_frame[data_frame['Input_2'] == value]
    filtered_data = filtered_data.sort_values(by='Input_1')

    source = ColumnDataSource(filtered_data)

    plot = figure(title=f"Input_2 = {value} fixed", 
                  x_range=filtered_data["Input_1"].unique(), 
                  height=300,
                  width=500
                  )

    plot.xaxis.axis_label = "Input_1"

    plot.vbar_stack(stackers=["Output_1", "Output_2", "Output_3"],
                    x="Input_1",
                    width=0.9,
                    color=["orange", "gray", "brown"],
                    source=source,
                    legend_label=["Output 1", "Output 2", "Output 3"]
                    )

    plots_for_input_2.append(plot)


grid_for_input_1 = gridplot(plots_for_input_1, ncols=1)  
grid_for_input_2 = gridplot(plots_for_input_2, ncols=1)

final_layout = row(grid_for_input_1, grid_for_input_2)


show(final_layout)

目标可视化效果示例

  • Bokeh示例图1:
    bokeh example plot 1
  • Bokeh示例图2:
    bokeh example plot 2

动态适配解决方案

核心思路

  1. 自动识别输入输出字段:通过列名前缀区分输入(Input_开头)和输出(Output_开头)字段
  2. 动态生成颜色映射:为每个输出字段分配唯一颜色,避免硬编码
  3. 通用化绘图逻辑:循环遍历所有输入字段,对每个输入字段固定时,生成对应可变输入的堆叠柱状图

完整代码实现

import pandas as pd
from bokeh.plotting import figure, output_file, show
from bokeh.layouts import gridplot, row
from bokeh.models import ColumnDataSource
from bokeh.palettes import Category20  # 用于生成动态颜色

# 读取Excel数据
data_frame = pd.read_excel("example.xlsx")

# 自动识别输入和输出字段
input_cols = [col for col in data_frame.columns if col.startswith('Input_')]
output_cols = [col for col in data_frame.columns if col.startswith('Output_')]

# 将所有输入字段转为字符串类型(确保x轴为分类值)
for col in input_cols:
    data_frame[col] = data_frame[col].astype(str)

# 生成输出字段对应的颜色和图例标签
output_colors = Category20[len(output_cols)] if len(output_cols) <=20 else Category20[20] + [f'#{i:06x}' for i in range(len(output_cols)-20)]
legend_labels = [col.replace('Output_', 'Output ') for col in output_cols]

output_file("dynamic_stacked_bar_charts.html")

all_plots = []

# 遍历每个输入字段,作为固定维度生成图表
for fixed_col in input_cols:
    # 获取当前固定字段的唯一值
    unique_fixed_values = data_frame[fixed_col].unique()
    plot_list = []
    
    # 为每个固定值生成堆叠图
    for fixed_val in unique_fixed_values:
        # 过滤数据:固定当前输入字段的值
        filtered_data = data_frame[data_frame[fixed_col] == fixed_val]
        # 确定可变的输入字段(除了当前固定的字段)
        variable_col = [col for col in input_cols if col != fixed_col][0]
        # 按可变字段排序
        filtered_data = filtered_data.sort_values(by=variable_col)
        
        source = ColumnDataSource(filtered_data)
        
        plot = figure(title=f"{fixed_col} = {fixed_val} fixed",
                      x_range=filtered_data[variable_col].unique(),
                      height=300,
                      width=500)
        
        plot.xaxis.axis_label = variable_col
        
        # 动态生成堆叠柱状图
        plot.vbar_stack(stackers=output_cols,
                        x=variable_col,
                        width=0.9,
                        color=output_colors,
                        source=source,
                        legend_label=legend_labels)
        
        plot.legend.location = "top_left"
        plot.legend.click_policy = "hide"  # 可选:添加图例隐藏交互
        
        plot_list.append(plot)
    
    # 将当前固定字段对应的所有图组成网格
    plot_grid = gridplot(plot_list, ncols=1)
    all_plots.append(plot_grid)

# 组合所有网格布局
final_layout = row(*all_plots)

show(final_layout)

代码说明

  • 字段自动识别:通过列表推导式筛选Input_和Output_开头的列,无需硬编码字段名
  • 动态颜色分配:使用Bokeh内置的Category20调色板,输出字段超过20个时自动生成额外颜色
  • 通用绘图循环:遍历每个输入字段作为固定维度,自动找到剩余的可变输入字段,生成对应堆叠图
  • 交互增强:添加了图例点击隐藏功能,提升用户体验

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 03:43:16