
Bokeh 不支持在同一图表中直接混合使用线性与对数 X 轴(因 x_range_name 绑定的范围类型必须与对应轴类型一致),但可通过预处理数据、合理设置对数范围(避开零值)并显式配置 LogAxis 与 extra_x_ranges 实现视觉等效效果。
bokeh 不支持在同一图表中直接混合使用线性与对数 x 轴(因 `x_range_name` 绑定的范围类型必须与对应轴类型一致),但可通过预处理数据、合理设置对数范围(避开零值)并显式配置 `logaxis` 与 `extra_x_ranges` 实现视觉等效效果。
在 Bokeh 中为同一图表添加线性主 X 轴与对数副 X 轴(如底部第二 X 轴),需同时满足三个关键条件:轴类型匹配范围类型、对数范围严格为正、数据坐标正确绑定到对应 x_range_name。你遇到的“无刻度”和“散点仍按线性绘制”问题,根本原因在于 Range1d(start=0, end=115) 包含了 0——而对数刻度在 x ≤ 0 时数学上无定义,Bokeh 无法生成有效 tick 位置,进而导致 LogAxis 渲染失败,且绘图时若未显式指定 x_range_name 或范围类型不匹配,Bokeh 会默认回退至主线性范围。
✅ 正确做法如下:
-
修正对数范围: 将
extra_x_ranges["x2"]的start设为大于 0 的最小合理值(如0.1),确保整个区间为正:from bokeh.models import LogAxis, Range1d # 替换原 p.extra_x_ranges 行: p.extra_x_ranges = {"x2": Range1d(start=0.1, end=115)} -
显式使用
LogAxis并绑定x_range_name:p.add_layout(LogAxis(x_range_name="x2", axis_label="Log Data", axis_label_text_color="blue"), 'below')
-
确保绘图时明确指定
x_range_name:p.scatter('log_data', 'Altitude', color='blue', size=8, x_range_name='x2', # 关键:强制使用对数范围 source=ColumnDataSource(df))
⚠️ 重要注意事项:
- Bokeh 的
x_range_name是逻辑范围标识符,其底层数值范围(Range1d)必须与所添加轴的类型兼容:LogAxis要求Range1d的start > 0;若误用LinearAxis配合对数数据,视觉上虽显示,但刻度非对数分布。 - 主 X 轴(
x_axis_type='linear')与副 X 轴(LogAxis)可共存,但不能共享同一x_range_name;必须通过extra_x_ranges定义独立范围,并在绘图和轴添加时严格对应。 - 若数据含
≤0值(如你的log_data列中存在0),需预处理:df['log_data'] = df['log_data'].replace(0, np.nan).fillna(0.1)或过滤,否则散点将落在无效区域外(不可见)。
? 完整可运行示例(修复后):
import pandas as pd
import numpy as np
from bokeh.plotting import figure, show
from bokeh.models import LogAxis, Range1d, ColumnDataSource
from bokeh.layouts import gridplot
df = pd.DataFrame([['2024-06-21 06:22:38', 605.968389, 0.994548, 3],
['2024-06-21 06:22:39', 616.009398, 0.983443, 4],
['2024-06-21 06:22:40', 624.630573, 0.973647, 1],
['2024-06-21 06:22:41', 633.476367, 1.017651, 2],
['2024-06-21 06:22:42', 642.322161, 5.017651, 2],
['2024-06-21 06:22:43', 650.268389, 30.726555, 4],
['2024-06-21 06:22:44', 659.559398, 89.2359, 5],
['2024-06-21 06:22:45', 665.630573, 6.92018, 3],
['2024-06-21 06:22:47', 673.476367, 0.69398, 2],
['2024-06-21 06:22:48', 685.322161, 0.770802, 1],
['2024-06-21 06:22:49', 697.155939, 0.856488, 0],
['2024-06-21 06:22:51', 716.763057, 0.934408, 3],
['2024-06-21 06:22:52', 722.012345, 7.865522, 2]],
columns=['time', 'Altitude', 'log_data', 'linear_data'])
# 预处理:避免 log_data <= 0(替换 0 为最小正数)
df['log_data'] = np.where(df['log_data'] <= 0, 0.1, df['log_data'])
p = figure(title="Linear + Log X-Axes (Dual Scale)",
x_axis_label="Linear Data", y_axis_label="Altitude / km",
frame_height=900, frame_width=650,
x_axis_type='linear')
# 主线性曲线
p.line('linear_data', 'Altitude', line_color='red', line_width=2,
source=ColumnDataSource(df))
# 添加对数副 X 轴(关键:start > 0)
p.extra_x_ranges = {"x2": Range1d(start=0.1, end=115)}
p.add_layout(LogAxis(x_range_name="x2", axis_label="Log Data",
axis_label_text_color="blue"), 'below')
# 对数数据散点(显式绑定 x_range_name)
p.scatter('log_data', 'Altitude', color='blue', size=8,
x_range_name='x2', source=ColumnDataSource(df))
show(gridplot([[p]], width=700, height=900))? 总结:Bokeh 允许双 X 轴共存,但对数轴成功渲染的前提是 extra_x_ranges 中对应范围严格为正。若业务逻辑要求同时展示线性和对数关系,优先推荐此方案;若数据动态变化或含零/负值风险高,建议改用两个并排子图(gridplot)以保证鲁棒性与可维护性。

















