如何用Bokeh实现总和不超过1.0的12个联动Slider?
Bokeh实现12个Slider总和限制为1.0的交互逻辑
需求说明
使用Bokeh库实现12个Slider与12元素数组的交互:每个Slider的值与数组对应元素相乘;核心约束为所有Slider的数值总和不得超过1.0——当总和达到1.0时,必须先降低其他Slider的值才能调高目标Slider;总和未达1.0时,剩余额度可分配给其他Slider直至触顶。
修改后的完整代码
from bokeh.io import show from bokeh.models import ColumnDataSource, CustomJS, Slider from bokeh.layouts import column, row # 原始数组 base_array = [0, 0.25, 0.425, 0.0261420833, 0.035854375, 0.079944375, 0.0368772727, 0.0426204545, 0.228336818, 0.0216474074, 0.0172977778, 0.0586568889] # 初始化计算结果数组(初始为base_array各元素乘1) result_array = [x * 1 for x in base_array] # 创建数据源 source = ColumnDataSource(data=dict(base=base_array, result=result_array)) # 生成12个Slider,初始值1,范围0-2,步长0.05 sliders = [] for i in range(12): slider = Slider(start=0, end=2, value=1, step=0.05, title=f"Slider {i+1}") sliders.append(slider) # 定义CustomJS回调函数,处理总和限制与数值计算 callback = CustomJS( args=dict(source=source, sliders=sliders), code=""" const base = source.data['base']; const result = source.data['result']; const totalLimit = 1.0; // 计算当前所有滑块的总和 let currentTotal = 0; sliders.forEach(slider => { currentTotal += slider.value; }); // 获取触发本次回调的滑块 const targetSlider = cb_obj; // 如果总和超过限制,修正滑块值 if (currentTotal > totalLimit) { // 计算超出量 const excess = currentTotal - totalLimit; // 将目标滑块的值调整为刚好让总和等于限制值 targetSlider.value = targetSlider.value - excess; // 重新计算总和 currentTotal = totalLimit; } // 更新结果数组:每个base元素乘对应滑块值 sliders.forEach((slider, index) => { result[index] = base[index] * slider.value; }); // 触发数据源更新 source.change.emit(); """ ) # 为每个滑块绑定回调 for slider in sliders: slider.js_on_change('value', callback) # 布局并显示 layout = row(column(*sliders)) show(layout)
关键逻辑说明
- 滑块批量生成:通过循环创建12个Slider,简化重复代码
- 总和校验与修正:在回调中实时计算所有滑块值的总和,若超过1.0则自动修正触发调整的滑块值,确保总和不超限
- 结果数组更新:每次滑块值变化后,重新计算
base_array各元素与对应滑块值的乘积,更新数据源 - 回调绑定:所有滑块共享同一个回调函数,确保任何滑块调整都会触发总和校验与结果更新
内容的提问来源于stack exchange,提问作者Dr. Merkwürdigliebe
相关产品推荐
相关产品推荐

