
bokeh 默认不支持直接用字符串(如 "0:00")作为横坐标绘制图表,必须显式指定分类轴或转换为 datetime 类型才能正确渲染。
bokeh 默认不支持直接用字符串(如 "0:00")作为横坐标绘制图表,必须显式指定分类轴或转换为 datetime 类型才能正确渲染。
在 Bokeh 中,当您将横坐标(x 轴)设为字符串列表(例如 tempo = ["0:00", "1:00", ..., "23:00"]),Bokeh 不会自动推断其为有序时间刻度,而是将其视为无序的离散类别(categorical data)。此时若未显式配置分类范围(FactorRange),Bokeh 会因无法确定 x 轴因子顺序或范围而静默失败——图表可能空白、条形错位,甚至完全不渲染,但不抛出明显错误。
✅ 正确做法一:使用分类轴(推荐用于小时级标签)
若您仅需显示 "0:00" 到 "23:00" 这类文本标签(无需时间计算、缩放或连续时间语义),应显式设置 x_range 为 FactorRange:
from bokeh.models import FactorRange
# 替换原 figure 初始化部分:
plot_dados = figure(
title="Consumo da Estação ao Longo de 24 Horas",
x_axis_label="Tempo (horas)",
y_axis_label="Energia (kWh)",
x_range=FactorRange(factors=tempo) # ? 关键:显式传入所有因子
)
plot_dados.vbar(x='x', top='y', width=0.8, source=source_dados, color="red")同样需为 plot_cargas_bateria 和 plot_consumo_total 的 figure() 添加 x_range=FactorRange(factors=tempo)。否则三图 x 轴将不同步,导致布局错乱。
✅ 正确做法二:使用真实 datetime 轴(推荐用于时间序列分析)
若后续需支持时间缩放、跨天数据、或与 Pandas datetime 对齐,应将 tempo 转为 datetime 对象:
from datetime import datetime, timedelta # 生成 24 小时 datetime 对象(以当天 00:00 为起点) tempo_dt = [datetime.now().date() + timedelta(hours=i) for i in range(24)] # 或固定日期(更稳妥): # tempo_dt = [datetime(2024, 1, 1, hour=i) for i in range(24)] # 更新数据源 source_dados = ColumnDataSource(data=dict(x=tempo_dt, y=dados)) source_cargas_bateria = ColumnDataSource(data=dict(x=tempo_dt, y=[0]*24)) source_consumo_total = ColumnDataSource(data=dict(x=tempo_dt, y=[0]*24))
Bokeh 会自动识别 datetime 类型并启用时间轴格式化(如 HH:mm),无需额外配置。此时 figure() 可保持默认,Bokeh 将正确渲染连续时间轴。
⚠️ 注意事项与调试建议
- 不要混用类型:确保所有 ColumnDataSource 的 x 字段类型一致(全为字符串 or 全为 datetime),且对应 figure.x_range 配置匹配。
- 验证数据源:在 update_plots() 结尾添加 print(source_dados.data['x'][:3]),确认更新后 x 值类型与初始一致。
- 避免隐式转换陷阱:Bokeh 不会将 "12:00" 自动转为 datetime;强制转换需在 Python 层完成。
- 性能提示:分类轴适合 ≤100 个因子;超大量级时间数据请务必用 datetime + DatetimeTickFormatter。
通过以上任一方式修正,您的三个柱状图将立即正常显示,并响应按钮更新——不再因 x 轴类型不匹配而“消失”。

















