Sliding through images with Bokeh Slider

扶醉桌前 提交于 2019-12-07 19:34:37

问题


I am trying to convey a large amount of scientific data seamlessly with the help of sliders.

I am beginning with Bokeh and have close to no knowledge in javascript. I tried to setup a first approach to be able to slide through two images, but I cannot get the image to refresh.

Suppose I have 1.png and 2.png in my folder.

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)

I adapted examples from Bokeh Widget Doc for the slider and working with images in bokeh.

My idea is that the slider, through the callbackimg snippet, will modify the source which contains the url, i.e the name of the image to load. I thought, for now, that a simple access to the string in the source, and a replacement through the current value of the slider (so it should jump from 1.png to 2.png as the slider goes from 1 to 2) should do the trick.

However, nothing is changing. I suspect I am doing something wrong in the Javascript snippet.

Thanks for any feedback

EDIT: I edited the code according to the suggestions of @bigreddot, but now the slider shows simply an empty figure when sliding in position '2'. EDIT2: Solved the issue, in my answer below


回答1:


The problem is this:

url = data['url'][0]
url.replace("1","f")

The replace method returns a new string (which you immediately discard), so you are not actually changing anything in the column data source. You need something like:

old = data['url'][0]
data['url'] = old.replace("1","f")



回答2:


@bigreddot answer is correct, but var f is a number, so in the replace, I need to write f.toString(10). Code that does what I want:

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)



回答3:


I have created a sample example where image changes as per the slider value. If slider value is 1 then app will display map-marker.png image and if value is 2 then app will display google_logo.png image.

With the help of Div you can do this task very easily.

map-marker.png

google_logo.png

Steps:

  1. Create a folder named 'image' in /usr/local/lib/python2.7/dist-packages/bokeh/server/static this path
  2. After creating folder in above mentioned location copy google_logo.png and map-marker.png images to /usr/local/lib/python2.7/dist-packages/bokeh/server/static/image this location. And save the following code as app.py and run it using bokeh serve app.py --show command.

    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 working

tested on bokeh version 0.12.13




回答4:


Another option is to create in advance a data source with all the image urls and use the slider to select the correct image.

Given the image names:

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

You can do:

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]))


来源:https://stackoverflow.com/questions/36985729/sliding-through-images-with-bokeh-slider

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!