如何在Bokeh/HoloViews热力图中处理时间与分类轴及刻度重叠问题?
解决Bokeh/HoloViews大分类y轴刻度重叠的问题
针对你遇到的3000+分类变量导致y轴刻度完全重叠的问题,结合Bokeh 1.2.0版本和Datashader的要求,这里有几个可靠的解决方案:
方法1:自定义JavaScript回调实现动态刻度(适配Bokeh 1.2.0)
Bokeh的默认分类轴不会自动根据缩放调整刻度数量,但你可以通过CustomJS监听视图的范围变化,动态生成仅包含可见区域内合适数量的刻度标签。
修改你的示例代码,添加y轴的动态刻度回调:
from datetime import datetime import pandas as pd import numpy as np from bokeh.plotting import figure, show from bokeh.transform import linear_cmap from bokeh.io import output_notebook from bokeh.models import CustomJS output_notebook() # 构建样本数据(模拟3000个分类) index = pd.date_range(start='1/1/2019', periods=1000, freq='T') data = np.random.rand(1000, 3000) columns = [f'col{n}' for n in range(3000)] df = pd.DataFrame(data=data, index=index, columns=columns) # 转换为Bokeh需要的格式 df = df.stack().reset_index() df.rename(columns={'level_0':'x','level_1':'y', 0:'z'},inplace=True) df.sort_values(by=['y'],inplace=True) x = [date.to_datetime64().astype('M8[ms]').astype('O') for date in df.x.to_list()] data = { 'value': df.z.to_list(), 'x': x, 'y': df.y.to_list(), 'date' : df.x.to_list() } # 创建绘图对象 p = figure(x_axis_type='datetime', y_range=columns, width=900, tooltips=[("x", "@date"), ("y", "@y"), ("value", "@value")]) p.rect(x='x', y='y', width=60*1000, height=1, line_color=None, fill_color=linear_cmap('value', 'Viridis256', low=df.z.min(), high=df.z.max()), source=data) # 自定义y轴动态刻度的JS回调 callback = CustomJS(args=dict(y_range=p.y_range), code=""" const range = y_range; const start = Math.floor(range.start); const end = Math.ceil(range.end); const total = end - start; // 控制显示的刻度数量,这里设置最多显示50个 const step = Math.max(Math.floor(total / 50), 1); const new_ticks = []; for (let i = start; i <= end; i += step) { new_ticks.push(range.factors[i]); } // 更新y轴刻度 if (new_ticks.length > 0) { y_range.factors = new_ticks; } """) # 绑定回调到y轴的范围变化事件 p.y_range.js_on_change('start', callback) p.y_range.js_on_change('end', callback) show(p)
这个回调会在用户缩放或平移y轴时,自动计算可见范围,生成间隔合适的刻度标签,避免重叠。
方法2:结合Datashader + HoloViews实现高效渲染与动态刻度
既然你必须使用Datashader,HoloViews配合Datashader可以更高效处理大分类数据,同时自动处理动态刻度:
import holoviews as hv from holoviews.operation.datashader import rasterize hv.extension('bokeh') # 复用之前的df数据(3000个分类) heatmap = hv.HeatMap(df, kdims=['x', 'y'], vdims='z') # 用Datashader光栅化处理大数据,动态适配视图 rasterized_heatmap = rasterize(heatmap, dynamic=True) # 设置绘图选项,优化y轴显示 rasterized_heatmap.opts( width=900, xaxis='datetime', yaxis='categorical', tools=['hover'], colorbar=True, cmap='Viridis256' ) # 渲染显示 hv.render(rasterized_heatmap)
HoloViews的dynamic=True会自动根据视图的缩放级别调整渲染内容,配合Bokeh的分类轴,能自动过滤掉不可见的刻度标签,既避免重叠又保证性能。
额外优化建议
- 若不需要显示所有分类的精确标签,可以设置y轴标签垂直排列,减少横向空间占用:
p.yaxis.major_label_orientation = 1.0 - 超大规模分类数据下,Datashader的光栅化是核心优化点,它会将大量分类数据转换为像素级渲染,避免Bokeh因渲染过多元素导致卡顿。
内容的提问来源于stack exchange,提问作者cadmaster
相关产品推荐
相关产品推荐

