使用 Bokeh Slider 在图像中滑动
Sliding through images with Bokeh Slider
我正在尝试借助滑块无缝地传达大量科学数据。
我刚开始使用 Bokeh,对 javascript 几乎一无所知。我尝试设置第一种方法来滑动两张图片,但我无法刷新图片。
假设我的文件夹中有 1.png 和 2.png。
from bokeh.io import vform
from bokeh.models import CustomJS, ColumnDataSource, Slider
from bokeh.plotting import Figure, output_file, show
output_file('image.html')
source = ColumnDataSource(data=dict(url=['1.png']))
p = Figure(x_range=(0,1), y_range=(0,1))
callbackimg = CustomJS(args=dict(source=source), code="""
var data = source.get('data');
var f = cb_obj.get('value')
old = data['url'][0]
data['url'][0]= old.replace("1","f")
source.trigger('change');
""")
p.image_url('url',source=source, x=0, y=1,w=1,h=1)
slider = Slider(start=1, end=2, value=1, step=1, title="image number", callback=callbackimg)
layout = vform(slider, p)
show(layout)
我为滑块改编了 Bokeh Widget Doc 中的示例,
。
我的想法是,滑块通过 callbackimg 片段修改包含 url 的源,即要加载的图像的名称。
我想,现在,可以简单地访问源中的字符串,并通过滑块的当前值进行替换(因此当滑块从 1 开始时,它应该从 1.png 跳到 2.png到 2) 应该可以解决问题。
然而,一切都没有改变。我怀疑我在 Javascript 片段中做错了什么。
感谢任何反馈
编辑:我根据@bigreddot 的建议编辑了代码,但现在滑块在位置“2”滑动时只显示一个空图形。
EDIT2:解决了这个问题,在我下面的回答中
问题是这样的:
url = data['url'][0]
url.replace("1","f")
replace
方法 returns 一个 new 字符串(您立即丢弃),因此您实际上并没有更改列数据源中的任何内容。你需要这样的东西:
old = data['url'][0]
data['url'] = old.replace("1","f")
@bigreddot 答案是正确的,但是 var f 是一个数字,所以在替换中,我需要写 f.toString(10)。
执行我想要的代码:
from bokeh.io import vform
from bokeh.models import CustomJS, ColumnDataSource, Slider
from bokeh.plotting import Figure, output_file, show
output_file('image.html')
source = ColumnDataSource(data=dict(url=['1.png']))
p = Figure(x_range=(0,1), y_range=(0,1))
callbackimg = CustomJS(args=dict(source=source), code="""
var data = source.get('data');
var f = cb_obj.get('value')
old = data['url'][0]
data['url'][0]= old.replace("1",f.toString(10))
source.trigger('change');
""")
p.image_url('url',source=source, x=0, y=1,w=1,h=1)
slider = Slider(start=1, end=2, value=1, step=1, title="image number", callback=callbackimg)
layout = vform(slider, p)
show(layout)
我创建了一个示例,其中图像根据滑块值变化。如果滑块值为 1,则应用程序将显示 map-marker.png 图像,如果值为 2,则应用程序将显示 google_logo.png 图像。
在 Div 的帮助下,您可以轻松完成此任务。
map-marker.png
google_logo.png
步骤:
- 在/usr/local/lib/python2.7/dist-packages/bokeh/server/static这个路径
中创建一个名为'image'的文件夹
在上述位置创建文件夹后,将google_logo.png和map-marker.png图像复制到/usr/local/lib/python2.7/dist-packages/bokeh/server/static/image 这个位置。并使用 bokeh serve app.py --show 命令将以下代码保存为 app.py 和 运行。
from bokeh.io import curdoc
from bokeh.layouts import row
from bokeh.models.widgets import Slider, Div
def change_img(attr, old, new):
if slider.value == 1:
logo.text = """<img src="static/image/map-marker.png" alt="logo">"""
else:
logo.text = """<img src="static/image/google_logo.png" alt="logo">"""
slider = Slider(start=1, end=2, value=1, title="image number")
slider.on_change('value', change_img)
logo = Div(text="""<img src="static/image/logo.png" alt="logo">""")
curdoc().add_root(row(slider,logo))
curdoc().title = "Image Demo"
app.py 工作
在散景版本 0.12.13 上测试
另一种选择是预先创建一个包含所有图像 url 的数据源,然后使用滑块 select 正确的图像。
给定图像名称:
import pandas as pd
imgs = ['1.png', '2.png', '3.png']
df = pd.DataFrame(imgs, columns=['imgs'])
print(df.head())
imgs
0 1.png
1 2.png
2 3.png
你可以这样做:
from bokeh.layouts import layout
from bokeh.plotting import figure, show
from bokeh.models import CustomJS, Slider, ColumnDataSource
source = ColumnDataSource(df)
p = figure(x_range=(0,1), y_range=(0,1))
im = p.image_url(url=[source.data['imgs'][0]], x=0, y=1, w=1, h=1)
cb = CustomJS(args=dict(im=im, source=source), code="""
im.data_source.data['url'] = [source.data['imgs'][cb_obj.value]];
im.data_source.change.emit();
""")
slider = Slider(start=0, end=2, value=0, step=1, title="image number", callback=cb)
show(layout([slider, p]))
我正在尝试借助滑块无缝地传达大量科学数据。
我刚开始使用 Bokeh,对 javascript 几乎一无所知。我尝试设置第一种方法来滑动两张图片,但我无法刷新图片。
假设我的文件夹中有 1.png 和 2.png。
from bokeh.io import vform
from bokeh.models import CustomJS, ColumnDataSource, Slider
from bokeh.plotting import Figure, output_file, show
output_file('image.html')
source = ColumnDataSource(data=dict(url=['1.png']))
p = Figure(x_range=(0,1), y_range=(0,1))
callbackimg = CustomJS(args=dict(source=source), code="""
var data = source.get('data');
var f = cb_obj.get('value')
old = data['url'][0]
data['url'][0]= old.replace("1","f")
source.trigger('change');
""")
p.image_url('url',source=source, x=0, y=1,w=1,h=1)
slider = Slider(start=1, end=2, value=1, step=1, title="image number", callback=callbackimg)
layout = vform(slider, p)
show(layout)
我为滑块改编了 Bokeh Widget Doc 中的示例,
我的想法是,滑块通过 callbackimg 片段修改包含 url 的源,即要加载的图像的名称。 我想,现在,可以简单地访问源中的字符串,并通过滑块的当前值进行替换(因此当滑块从 1 开始时,它应该从 1.png 跳到 2.png到 2) 应该可以解决问题。
然而,一切都没有改变。我怀疑我在 Javascript 片段中做错了什么。
感谢任何反馈
编辑:我根据@bigreddot 的建议编辑了代码,但现在滑块在位置“2”滑动时只显示一个空图形。 EDIT2:解决了这个问题,在我下面的回答中
问题是这样的:
url = data['url'][0]
url.replace("1","f")
replace
方法 returns 一个 new 字符串(您立即丢弃),因此您实际上并没有更改列数据源中的任何内容。你需要这样的东西:
old = data['url'][0]
data['url'] = old.replace("1","f")
@bigreddot 答案是正确的,但是 var f 是一个数字,所以在替换中,我需要写 f.toString(10)。 执行我想要的代码:
from bokeh.io import vform
from bokeh.models import CustomJS, ColumnDataSource, Slider
from bokeh.plotting import Figure, output_file, show
output_file('image.html')
source = ColumnDataSource(data=dict(url=['1.png']))
p = Figure(x_range=(0,1), y_range=(0,1))
callbackimg = CustomJS(args=dict(source=source), code="""
var data = source.get('data');
var f = cb_obj.get('value')
old = data['url'][0]
data['url'][0]= old.replace("1",f.toString(10))
source.trigger('change');
""")
p.image_url('url',source=source, x=0, y=1,w=1,h=1)
slider = Slider(start=1, end=2, value=1, step=1, title="image number", callback=callbackimg)
layout = vform(slider, p)
show(layout)
我创建了一个示例,其中图像根据滑块值变化。如果滑块值为 1,则应用程序将显示 map-marker.png 图像,如果值为 2,则应用程序将显示 google_logo.png 图像。
在 Div 的帮助下,您可以轻松完成此任务。
map-marker.png
google_logo.png
步骤:
- 在/usr/local/lib/python2.7/dist-packages/bokeh/server/static这个路径 中创建一个名为'image'的文件夹
在上述位置创建文件夹后,将google_logo.png和map-marker.png图像复制到/usr/local/lib/python2.7/dist-packages/bokeh/server/static/image 这个位置。并使用 bokeh serve app.py --show 命令将以下代码保存为 app.py 和 运行。
from bokeh.io import curdoc from bokeh.layouts import row from bokeh.models.widgets import Slider, Div def change_img(attr, old, new): if slider.value == 1: logo.text = """<img src="static/image/map-marker.png" alt="logo">""" else: logo.text = """<img src="static/image/google_logo.png" alt="logo">""" slider = Slider(start=1, end=2, value=1, title="image number") slider.on_change('value', change_img) logo = Div(text="""<img src="static/image/logo.png" alt="logo">""") curdoc().add_root(row(slider,logo)) curdoc().title = "Image Demo"
在散景版本 0.12.13 上测试
另一种选择是预先创建一个包含所有图像 url 的数据源,然后使用滑块 select 正确的图像。
给定图像名称:
import pandas as pd
imgs = ['1.png', '2.png', '3.png']
df = pd.DataFrame(imgs, columns=['imgs'])
print(df.head())
imgs
0 1.png
1 2.png
2 3.png
你可以这样做:
from bokeh.layouts import layout
from bokeh.plotting import figure, show
from bokeh.models import CustomJS, Slider, ColumnDataSource
source = ColumnDataSource(df)
p = figure(x_range=(0,1), y_range=(0,1))
im = p.image_url(url=[source.data['imgs'][0]], x=0, y=1, w=1, h=1)
cb = CustomJS(args=dict(im=im, source=source), code="""
im.data_source.data['url'] = [source.data['imgs'][cb_obj.value]];
im.data_source.change.emit();
""")
slider = Slider(start=0, end=2, value=0, step=1, title="image number", callback=cb)
show(layout([slider, p]))