在散景中使用滑块浏览图像序列
browsing image sequence with a slider in bokeh
我正在尝试使用 Bokeh 显示一系列图像,并希望以交互方式滑过或播放该序列。当我 运行 我的脚本显示第一张图像时,但当我拖动滑块或单击播放按钮时图像没有更新。我的代码如下:
import numpy as np
import bokeh.io
from bokeh.plotting import figure
from bokeh.io import curdoc
from bokeh.layouts import layout
from bokeh.models import ColumnDataSource, HoverTool, SingleIntervalTicker, Slider, Button, Label
from bokeh.palettes import Spectral1
from skimage.external import tifffile as T
img=T.imread('C:/Users/UserXX/Desktop/Image_Sequence.tif')
sources={}
frames=list(range(0,img.shape[0]))
for frame in frames:
sources[frame]=ColumnDataSource(data=dict(image=[img[frame,:,:]]))
source1 = sources[0]
p_img = figure(plot_width=694, plot_height=520, x_range=[0,1388], y_range=[0, 1040])
label = Label(x=1.1, y=18, text=str(frames[0]), text_font_size='70pt', text_color='#eeeeee')
p_img.add_layout(label)
p_img.image(image='image', x=[0], y=[0], dw=[1388], dh=[1040],source=source1, palette="Spectral11")
slider = Slider(start=frames[0], end=frames[-1], value=frames[0],step=1, title="Frame")
def animate_update():
frame = slider.value + 1
if frame > frames[-1]:
frame = frames[0]
slider.value = frame
def slider_update(attr, old, new):
global source
global sources
frame = slider.value
label.text = str(frame)
source= sources[frame]
slider.on_change('value', slider_update)
def animate():
if button.label == '► Play':
button.label = '❚❚ Pause'
curdoc().add_periodic_callback(animate_update, 200)
else:
button.label = '► Play'
curdoc().remove_periodic_callback(animate_update)
button = Button(label='► Play', width=60)
button.on_click(animate)
l = layout([[p_img],[slider, button],], sizing_mode='scale_width')
curdoc().add_root(l)
curdoc().title = "Image_Sequence"
我以此为例:
https://github.com/bokeh/bokeh/blob/master/examples/app/gapminder/main.py
我不确定将新图像数据传递给源的方式是否正确。
有什么建议吗?
您的代码中有一些不同的地方需要修复或改进,因此研究和模拟这个简化的完整工作示例可能更容易:
import numpy as np
from bokeh.io import curdoc
from bokeh.layouts import column
from bokeh.models import ColumnDataSource, Slider
from bokeh.plotting import figure
N = 100
x_ = np.linspace(0, 10, 200)
y_ = np.linspace(0, 10, 200)
z_ = np.linspace(0, 10, N)
x, y, z = np.meshgrid(x_, y_, z_, indexing='xy')
data = np.sin(x+z)*np.cos(y)
source = ColumnDataSource(data=dict(image=[data[:, :, 0]]))
p = figure(x_range=(0, 10), y_range=(0, 10))
p.image(image='image', x=0, y=0, dw=10, dh=10, source=source, palette="Spectral11")
slider = Slider(start=0, end=(N-1), value=0, step=1, title="Frame")
def update(attr, old, new):
source.data = dict(image=[data[:, :, slider.value]])
slider.on_change('value', update)
curdoc().add_root(column(p, slider))
请注意,每次滑块更改时都会进行更新,即使是 200x200 的内容也可能开始变得有些滞后(至少在我的系统上是这样)。因此,您可能还想考虑
中描述的技术
基于@bigreddot 的示例。当拖动滑块或单击按钮时,我的代码可以更新图像。虽然对于较大尺寸的图像,它们更新非常缓慢。
import numpy as np
from bokeh.plotting import figure,ColumnDataSource
from bokeh.io import curdoc
from bokeh.layouts import layout
from bokeh.models import Slider, Button, Label
from bokeh.palettes import Spectral11
from skimage.external import tifffile as T
img_o=T.imread('C:/Users/UserXX/Desktop/Image_Sequence.tif')
frames=list(range(0,img_o.shape[0]))
img=np.flip(img_o,1)
source = ColumnDataSource(data=dict(image=[img[0,:,:]]))
p_img = figure(x_range=(0,1388), y_range=(0, 1040))
label = Label(x=1.1, y=18, text=str(frames[0]), text_font_size='70pt', text_color='#eeeeee')
p_img.add_layout(label)
im=p_img.image(image='image', x=0, y=0, dw=1388, dh=1040, source=source, palette="Spectral11")
slider = Slider(start=frames[0], end=frames[-1], value=frames[0],step=1, title="Frame")
def animate_update():
frame = slider.value + 1
if frame > frames[-1]:
frame = frames[0]
slider.value = frame
ds=im.data_source
def slider_update(attr, old, new):
new_data=dict()
frame = slider.value
label.text = str(frame)
new_data['image']=[img[frame,:,:]]
ds.data= new_data
slider.on_change('value', slider_update)
def animate():
if button.label == '► Play':
button.label = '❚❚ Pause'
curdoc().add_periodic_callback(animate_update, 200)
else:
button.label = '► Play'
curdoc().remove_periodic_callback(animate_update)
button = Button(label='► Play', width=60)
button.on_click(animate)
l = layout([[p_img],[slider,button],], sizing_mode='scale_width')
curdoc().add_root(l)
curdoc().title = "Image_sequence"
我主要改变了数据传递给源的方式。
另一件事是这条线不起作用(第一帧被绘制但未更新)
im=p_img.image(image='image', x=[0], y=[0], dw=[1388], dh=[1040], source=source, palette="Spectral11")
我改成之后:
im=p_img.image(image='image', x=0, y=0, dw=1388, dh=1040, source=source, palette="Spectral11")
图片可以更新了。
唯一的区别是 [ ] 从参数 x, y, dw, dh 中去掉。但是不知道为什么会出问题
我正在尝试使用 Bokeh 显示一系列图像,并希望以交互方式滑过或播放该序列。当我 运行 我的脚本显示第一张图像时,但当我拖动滑块或单击播放按钮时图像没有更新。我的代码如下:
import numpy as np
import bokeh.io
from bokeh.plotting import figure
from bokeh.io import curdoc
from bokeh.layouts import layout
from bokeh.models import ColumnDataSource, HoverTool, SingleIntervalTicker, Slider, Button, Label
from bokeh.palettes import Spectral1
from skimage.external import tifffile as T
img=T.imread('C:/Users/UserXX/Desktop/Image_Sequence.tif')
sources={}
frames=list(range(0,img.shape[0]))
for frame in frames:
sources[frame]=ColumnDataSource(data=dict(image=[img[frame,:,:]]))
source1 = sources[0]
p_img = figure(plot_width=694, plot_height=520, x_range=[0,1388], y_range=[0, 1040])
label = Label(x=1.1, y=18, text=str(frames[0]), text_font_size='70pt', text_color='#eeeeee')
p_img.add_layout(label)
p_img.image(image='image', x=[0], y=[0], dw=[1388], dh=[1040],source=source1, palette="Spectral11")
slider = Slider(start=frames[0], end=frames[-1], value=frames[0],step=1, title="Frame")
def animate_update():
frame = slider.value + 1
if frame > frames[-1]:
frame = frames[0]
slider.value = frame
def slider_update(attr, old, new):
global source
global sources
frame = slider.value
label.text = str(frame)
source= sources[frame]
slider.on_change('value', slider_update)
def animate():
if button.label == '► Play':
button.label = '❚❚ Pause'
curdoc().add_periodic_callback(animate_update, 200)
else:
button.label = '► Play'
curdoc().remove_periodic_callback(animate_update)
button = Button(label='► Play', width=60)
button.on_click(animate)
l = layout([[p_img],[slider, button],], sizing_mode='scale_width')
curdoc().add_root(l)
curdoc().title = "Image_Sequence"
我以此为例: https://github.com/bokeh/bokeh/blob/master/examples/app/gapminder/main.py 我不确定将新图像数据传递给源的方式是否正确。 有什么建议吗?
您的代码中有一些不同的地方需要修复或改进,因此研究和模拟这个简化的完整工作示例可能更容易:
import numpy as np
from bokeh.io import curdoc
from bokeh.layouts import column
from bokeh.models import ColumnDataSource, Slider
from bokeh.plotting import figure
N = 100
x_ = np.linspace(0, 10, 200)
y_ = np.linspace(0, 10, 200)
z_ = np.linspace(0, 10, N)
x, y, z = np.meshgrid(x_, y_, z_, indexing='xy')
data = np.sin(x+z)*np.cos(y)
source = ColumnDataSource(data=dict(image=[data[:, :, 0]]))
p = figure(x_range=(0, 10), y_range=(0, 10))
p.image(image='image', x=0, y=0, dw=10, dh=10, source=source, palette="Spectral11")
slider = Slider(start=0, end=(N-1), value=0, step=1, title="Frame")
def update(attr, old, new):
source.data = dict(image=[data[:, :, slider.value]])
slider.on_change('value', update)
curdoc().add_root(column(p, slider))
请注意,每次滑块更改时都会进行更新,即使是 200x200 的内容也可能开始变得有些滞后(至少在我的系统上是这样)。因此,您可能还想考虑
基于@bigreddot 的示例。当拖动滑块或单击按钮时,我的代码可以更新图像。虽然对于较大尺寸的图像,它们更新非常缓慢。
import numpy as np
from bokeh.plotting import figure,ColumnDataSource
from bokeh.io import curdoc
from bokeh.layouts import layout
from bokeh.models import Slider, Button, Label
from bokeh.palettes import Spectral11
from skimage.external import tifffile as T
img_o=T.imread('C:/Users/UserXX/Desktop/Image_Sequence.tif')
frames=list(range(0,img_o.shape[0]))
img=np.flip(img_o,1)
source = ColumnDataSource(data=dict(image=[img[0,:,:]]))
p_img = figure(x_range=(0,1388), y_range=(0, 1040))
label = Label(x=1.1, y=18, text=str(frames[0]), text_font_size='70pt', text_color='#eeeeee')
p_img.add_layout(label)
im=p_img.image(image='image', x=0, y=0, dw=1388, dh=1040, source=source, palette="Spectral11")
slider = Slider(start=frames[0], end=frames[-1], value=frames[0],step=1, title="Frame")
def animate_update():
frame = slider.value + 1
if frame > frames[-1]:
frame = frames[0]
slider.value = frame
ds=im.data_source
def slider_update(attr, old, new):
new_data=dict()
frame = slider.value
label.text = str(frame)
new_data['image']=[img[frame,:,:]]
ds.data= new_data
slider.on_change('value', slider_update)
def animate():
if button.label == '► Play':
button.label = '❚❚ Pause'
curdoc().add_periodic_callback(animate_update, 200)
else:
button.label = '► Play'
curdoc().remove_periodic_callback(animate_update)
button = Button(label='► Play', width=60)
button.on_click(animate)
l = layout([[p_img],[slider,button],], sizing_mode='scale_width')
curdoc().add_root(l)
curdoc().title = "Image_sequence"
我主要改变了数据传递给源的方式。 另一件事是这条线不起作用(第一帧被绘制但未更新)
im=p_img.image(image='image', x=[0], y=[0], dw=[1388], dh=[1040], source=source, palette="Spectral11")
我改成之后:
im=p_img.image(image='image', x=0, y=0, dw=1388, dh=1040, source=source, palette="Spectral11")
图片可以更新了。 唯一的区别是 [ ] 从参数 x, y, dw, dh 中去掉。但是不知道为什么会出问题