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

如何单独控制三级bokeh.models.FactorRange的各层级刻度标签?

我太懂你这种纠结了——用bokeh.models.FactorRange做三级分类的vbar图时,默认的刻度控制简直像个“一刀切”的工具,要么底层标签挤成一团,要么只能粗暴隐藏,连层级单独设置的选项都没有。别慌,给你几个实用的解决办法,从优雅到进阶都有:

一、精准控制各层级标签的显示(替代隐藏标签的权宜之计)

与其用PrintfTickFormatter(format='')粗暴隐藏底层标签,不如用FuncTickFormatter自定义逻辑,精准控制每一层的显示内容,还能避免上层标签重复出现,从根源解决拥挤问题。

假设你的三级因子是类似[("大类A", "中类1", "小项1"), ("大类A", "中类1", "小项2"), ...]的结构,代码示例如下:

from bokeh.models import FactorRange, FuncTickFormatter

# 定义你的三级因子范围
x_range = FactorRange(factors=your_three_level_factor_list)

# 自定义刻度格式化逻辑
plot.xaxis.formatter = FuncTickFormatter(code="""
    // 把Bokeh传入的因子字符串拆分成三个层级
    const parts = tick.replace(/[()]/g, '').split(', ');
    if (parts.length !== 3) return tick;

    // 获取上一个刻度的层级,避免重复显示上层标签
    const prevTick = ticks[tickIndex - 1];
    const prevParts = prevTick ? prevTick.replace(/[()]/g, '').split(', ') : [];

    // 逻辑:仅当当前项是新的中类时显示中类标签,新的大类时显示大类标签,小项标签隐藏
    if (prevParts[1] !== parts[1]) {
        return parts[1];
    } else if (prevParts[0] !== parts[0]) {
        return parts[0];
    } else {
        return '';
    }
""")

这个逻辑会自动帮你去重上层标签,同时隐藏底层的小项标签,既整洁又保留了分类层级的可读性。

二、单独旋转第二层刻度标签

默认的major_label_orientation确实只作用于最底层,但我们可以通过添加额外的Axis对象来单独控制第二层标签的样式,步骤很简单:

from bokeh.models import Axis, FactorRangeTicker

# 先把默认x轴的标签隐藏(只留刻度线)
plot.xaxis.major_label_text_font_size = '0pt'

# 准备去重后的第二层因子列表(避免重复标签)
unique_second_level = list({factor[1] for factor in your_three_level_factor_list})

# 创建专门对应第二层的轴
second_level_axis = Axis(
    ticker=FactorRangeTicker(factors=unique_second_level),
    major_label_orientation=3.14/4,  # 用弧度表示45度旋转
    major_label_text_font_size='10pt',
    location='below',
    axis_label_standoff=15  # 调整标签和刻度线的距离,避免重叠
)
# 添加到图中
plot.add_layout(second_level_axis, 'below')

这样就能单独给第二层标签设置旋转角度,完全不影响其他层级。

三、进阶方案:用原生CategoricalAxis实现层级控制

如果你的Bokeh版本在2.4.0及以上,官方已经提供了原生的层级控制支持——CategoricalAxis,直接用参数就能分别设置不同层级的标签样式,这是最优雅的解决方式:

from bokeh.models import CategoricalAxis

# 替换默认的x轴为CategoricalAxis
plot.xaxis = CategoricalAxis(
    group_label_orientation=0,  # 第一层(大类)标签不旋转
    subgroup_label_orientation=3.14/4,  # 第二层(中类)标签45度旋转
    minor_label_text_font_size='0pt',  # 隐藏第三层(小项)标签解决拥挤
    subgroup_label_standoff=20  # 调整第二层标签的间距
)

这个方法不需要写自定义JS逻辑,直接通过参数就能搞定所有需求,推荐优先使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:50:14