如何用Bokeh制作带Scrubber组件的动画并导出为HTML?
用Bokeh实现带进度条(Scrubber)的动画并导出HTML
需求背景
原本在Matplotlib中可通过FuncAnimation制作动画,并用to_jshtml()导出包含进度条(Scrubber)的HTML。现在需要在Bokeh中实现相同功能,同时利用Bokeh的定制化特性。
实现方案
Bokeh可以通过Slider组件作为进度条,结合JavaScript回调实现帧切换,最终导出独立HTML文件。以下是与Matplotlib示例对应的完整可复现代码:
import xarray as xr from bokeh.plotting import figure, save from bokeh.models import LinearColorMapper, ColorBar, Slider, CustomJS, ColumnDataSource from bokeh.layouts import column from bokeh.palettes import Coolwarm # 加载并处理数据,与Matplotlib示例保持一致 ds = xr.tutorial.open_dataset('air_temperature') tas = ds.air - 273.15 frames = 40 # 准备初始帧数据 initial_data = tas[0, :, :].values x = tas.lon.values y = tas.lat.values time_values = [str(t)[:13] for t in tas.coords['time'].values[:frames]] # 创建颜色映射,对应coolwarm色阶 color_mapper = LinearColorMapper(palette=Coolwarm[256], vmin=-40, vmax=40) # 创建数据源,用于动态更新 source = ColumnDataSource(data={'image': [initial_data], 'x': [x[0]], 'y': [y[0]], 'dw': [x[-1]-x[0]], 'dh': [y[-1]-y[0]]}) # 创建绘图对象 p = figure(title=f"Time = {time_values[0]}", x_range=(x.min(), x.max()), y_range=(y.min(), y.max()), width=800, height=400) # 添加图像图层 p.image(image='image', x='x', y='y', dw='dw', dh='dh', source=source, color_mapper=color_mapper) # 添加颜色条 color_bar = ColorBar(color_mapper=color_mapper, label_standoff=12, location=(0,0)) p.add_layout(color_bar, 'right') # 创建进度条(Slider) slider = Slider(start=0, end=frames-1, value=0, step=1, title="Frame") # 编写回调函数,实现进度条控制帧切换 callback = CustomJS(args=dict(source=source, slider=slider, time_values=time_values, tas_data=tas.values[:frames], p=p), code=""" const frame = slider.value; // 更新图像数据 source.data['image'] = [tas_data[frame]]; // 更新标题 p.title.text = `Time = ${time_values[frame]}`; source.change.emit(); """) # 将回调绑定到进度条 slider.js_on_change('value', callback) # 可选:添加播放按钮实现自动播放 from bokeh.models import Button play_button = Button(label="Play", button_type="success") play_callback = CustomJS(args=dict(slider=slider, frames=frames), code=""" let is_playing = false; let interval; if (!is_playing) { is_playing = true; this.label = "Pause"; interval = setInterval(() => { let next_frame = slider.value + 1; if (next_frame >= frames) next_frame = 0; slider.value = next_frame; }, 200); this.interval = interval; } else { is_playing = false; this.label = "Play"; clearInterval(this.interval); } """) play_button.js_on_click(play_callback) # 布局组件并导出HTML layout = column(p, slider, play_button) save(layout, "bokeh_animation_scrubber.html")
关键细节说明
- 进度条控制:通过
Slider组件的value变化触发CustomJS回调,动态更新图像数据和标题,实现拖拽进度条切换帧的功能。 - 颜色映射:用
LinearColorMapper匹配Matplotlib的coolwarm色阶,保证视觉效果一致。 - 导出HTML:调用
save()方法直接生成独立HTML文件,无需依赖Jupyter环境,打开即可交互。 - 定制扩展:示例中额外添加了播放/暂停按钮,可根据需求扩展更多交互(如调整播放速度、添加帧标签等)。
内容的提问来源于stack exchange,提问作者Leonel Quiroz
相关产品推荐
相关产品推荐

