2017-03-12 78 views
1

我試圖用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 我不知道如果我是新的圖像數據傳遞到源的方式是否正確。 有什麼建議嗎?

+0

嘗試用source1.data = sources [frame] .data替換source = sources [frame]。由於該圖的來源爲source1,因此您需要更改source1的關聯數據。否則,移動滑塊只是定義源而不是source1,它正在繪製。如果這不起作用嘗試複製你的例子。 – Anthonydouc

回答

0

有這需要修復或者在你的代碼提高了一些不同的東西,所以它可能只是更容易學習和效仿這一簡化的完整工作示例:

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的東西也可能會稍微有點遲緩(至少在我的系統上)。所以,你可能還需要考慮所描述的技術,Throttling in Bokeh application

enter image description here

+0

我模擬你的例子,並且在拖動滑塊時確實更新了我的圖像。然而,圖像更新非常緩慢,每幀> 3s。每幀的大小是1040X1388​​。但是當我使用尺寸更小的圖像(100X100)時,它會更新得非常快。我猜這是在本文中提到的同一問題: http://stackoverflow.com/questions/40908166/efficient-updates-of-image-plots-in-bokeh-for-interactive-visualization?rq=1 –

+0

我仍然想要逐幀看到變化的過程,但速度更快。所以我不想在Bokeh中使用Throttling。將看看是否有其他方法來解決這個問題。 –

+0

如果節流不是一個選項,則Bokeh可能不是當前用例的正確工具。 base64二進制編碼的PR已經合併,可以從鏈接的SO問題中大大改善,上面的圖像已經反映了它的包含。在服務器應用程序中使用零拷貝直接傳輸數組緩衝區有可能進一步改進,但這將是未來的工作。即使如此,我仍然不確定這足以支持對尺寸不同的圖像進行快速交互。 – bigreddot

0

基礎上@ 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中除掉。但我不知道爲什麼會導致問題。

+0

字形方法參數可以*全部*爲數據源列名稱或* all *是序列文字(在這種情況下,CDS是在幕後製作的)。他們不能混合那些東西,這就是上面第一行所發生的事情。 – bigreddot