1

I have a Bokeh app which I want to run in a Streamlit app. I know Streamlit supports certain Bokeh elements, but I am struggling to get my specific Bokeh app working on Streamlit.

The Bokeh app is basically a slider which controls a certain image being shown. I know you can also do this solely in Streamlit, but as Streamlit always completely reruns the app when changing the slider, this gives bad performance (the images take a second to load). In the below Bokeh example the images are shown very fast when changing the slider input.

from bokeh.io import curdoc
from bokeh.layouts import row, column
from bokeh.models.widgets import Slider, Div

def change_img(attr, old, new):
    logo.text = """<img src="https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/{}.png" alt="div_image" width="200" height="200">""".format(slider.value)

slider = Slider(start=1, end=10, step=1, value=1, title="image number")
slider.on_change('value', change_img)
logo = Div(text="""<img src="https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/{}.png"  alt="logo" width="200" height="200">""".format(slider.value), width=200, height=200)

curdoc().add_root(column(logo, slider))

I found another similar question with a good answer from @Timeless see: https://stackoverflow.com/a/78543137/15692146

In this answer he is controlling the bokeh viewer with a variable 'p'.
I tried rewriting this example to use this variable 'p' to update my logo.text from the example code above, like this:

import streamlit as st
import streamlit.components.v1 as components
from bokeh.embed import file_html
from bokeh.layouts import column
from bokeh.models import ColumnDataSource, CustomJS, Slider, Div
from bokeh.plotting import figure
from bokeh.resources import CDN


def plot(p=1):
    x = [1]
    y = [p]

    source = ColumnDataSource(data=dict(x=x, y=y))
    print(source.data['y'][0])

    fig = figure()

    fig.title.align = "center"

    fig.vbar(x="x", top="y", width=0.5, source=source)

    def change_img(attr, old, new):
        logo.text = """<img src="https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/{}.png" alt="div_image">""".format(slider.value)

    logo = Div(text="""<img src="https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/{}.png"  alt="logo">""".format(source.data['y'][0]), width=200, height=200)

    slider = Slider(
        start=1,
        end=10,
        value=p,
        step=1,
    )

    slider.js_on_change(
        "value",
        CustomJS(
            args=dict(source=source),
            code="""
        const data = source.data;
        const p = cb_obj.value;
        data['y'] = [p];
        source.change.emit();
    """,
        ),
    )

    return file_html(column(logo, slider, fig), CDN)

components.html(plot(), height=1000)

But for some reason the slider changes aren't connect to the showing of the image created in 'logo'.

I feel like I am almost there, but I lack the JS and bokeh knowledge to really understand what is going on here.

Does someone see what I am missing why in the second code block the slider isn't connected to the logo div?

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.