如何解决Streamlit中Bokeh滑块无法联动图片展示的问题?
问题原因与解决方案
你的代码核心问题有两个:
- 嵌入到Streamlit的Bokeh应用是静态HTML,Python回调函数
change_img无法执行,必须改用JavaScript回调直接操作前端元素。 - 你当前的JS回调只更新了
ColumnDataSource,完全没处理logo这个Div组件,所以滑块变动不会触发图片更新。
另外,代码里的柱状图figure和ColumnDataSource是多余的,完全可以删掉以简化逻辑。
修正后的完整代码如下:
import streamlit as st import streamlit.components.v1 as components from bokeh.embed import file_html from bokeh.layouts import column from bokeh.models import CustomJS, Slider, Div from bokeh.resources import CDN def plot(p=1): # 初始化图片Div logo = Div( text=f"""<img src="https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/{p}.png" alt="logo" width="200" height="200">""", width=200, height=200 ) # 初始化滑块 slider = Slider( start=1, end=10, value=p, step=1, title="image number" ) # 给滑块绑定JS回调,直接操作logo组件 slider.js_on_change( "value", CustomJS( args=dict(logo=logo), # 将logo对象传入JS环境 code=""" // 获取滑块当前值 const imgNum = cb_obj.value; // 更新Div的text内容,替换图片URL中的数字 logo.text = `<img src="https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${imgNum}.png" alt="logo" width="200" height="200">`; """ ), ) # 返回嵌入用的HTML return file_html(column(logo, slider), CDN) components.html(plot(), height=400)
关键修改说明:
- 移除冗余组件:删掉了不需要的
figure和ColumnDataSource,聚焦滑块控制图片的核心需求。 - 改用JS回调:把原来的Python回调换成
CustomJS,直接在前端修改Div的内容,避免Streamlit全量重跑。 - 传递目标组件:在
CustomJS的args里传入logo对象,让JS代码可以直接访问并修改这个Div的text属性。 - 优化嵌入高度:调整
components.html的height为400,更贴合实际内容高度。
这样修改后,滑块拖动时会立刻触发JS代码更新图片,不会触发Streamlit的全量重跑,速度和原生Bokeh应用一致。
内容的提问来源于stack exchange,提问作者sam_cocha
相关产品推荐
相关产品推荐

