Not able to implement hover callback in bokeh on streamlit

Hello guys!

I am trying to use bokeh charts in streamlit for creating a scatterplot and also on hovering it shows an image of the datapoint. I am using streamlit 0.53 on python 3.6 on a ubuntu 18.04 machine.

I came across this post by @Marc and it has helped me a lot to come up with these visualizations but I am stuck at this last juncture for which I would be highly obliged if someone could guide me in the right direction.

The expected behaviour is as follows. When I export the figure to an html file, this is how it looks; I have hovered over the point (1,1) and this figure has popped up as a tooltip.

On streamlit however, this is how the chart output looks as follows, the tooltip doesn’t render the image…

The code that I have used to create these plots is as follows

import streamlit as st
import pandas as pd
from bokeh.plotting import figure, output_file, save
from bokeh.models.tools import HoverTool
from bokeh.models import ColumnDataSource
output_file(f"index.html")

p = figure(
    plot_width = 1500,
    plot_height = 900,
    title = f"Demo",
    x_axis_label = "X",
    y_axis_label = "Y",   
)

df = pd.read_csv("./demo.csv")

p.scatter(
    y = "y",
    x = "x",
    source = ColumnDataSource(df),
    size = 10,
)

hover = HoverTool()
hover.tooltips = """
    <div>
        <h2>Figure</h2>
        <div>
            <img src="@ImgName" alt="@ImgName" style="border:2px solid black; border-radius:20%" width="150"/>
        </div>
    </div>
"""

p.add_tools(hover)
save(p)

st.title("Visualization")
st.dataframe(df.head())
st.bokeh_chart(p, use_container_width=True)

The data in the csv files is as follows

x,y,ImgName
1,1,/home/vinayak/st_bokeh/pics/circle.png
1,2,/home/vinayak/st_bokeh/pics/parallelogram.png
2,1,/home/vinayak/st_bokeh/pics/square.png

Could someone please help me figure out what could the issue be here? If this works, it would be a really great step toward helping me visualize abnormalities in my dataset while doing Machine Learning.

Thanks & Regards,
Vinayak.

1 Like

I’m having this issue too β€” @ElisonSherton did you manage to resolve this issue? :pray:

Hello @ElisonSherton @ehknight

The long reason is here: Restrict Download of Images & Videos on Streamlit App - #2 by andfanilo

The Streamlit server serves static objects from its installation directory only, rather than your project workspace. You will need to copy/paste your png files to this directory so Bokeh refers them correctly.

The following worked on my side

import streamlit as st
import pathlib
import pandas as pd
import shutil
from bokeh.plotting import figure
from bokeh.models.tools import HoverTool
from bokeh.models import ColumnDataSource


# create a png_hack folder in Streamlit's static directory
STREAMLIT_STATIC_PATH = pathlib.Path(st.__path__[0]) / "static"
PNG_PATH = STREAMLIT_STATIC_PATH / "png_hack"

if not PNG_PATH.is_dir():
    PNG_PATH.mkdir()

# copy your PNG files to the static directory
for p in ["lol.png", "lol2.png", "lol12.png"]:
    if not (PNG_PATH / p).exists():
        shutil.copy("/workspace/" + p, PNG_PATH / p)

p = figure(
    plot_width=1500,
    plot_height=900,
    title=f"Demo",
    x_axis_label="X",
    y_axis_label="Y",
)


# static files are referred relative to the static directory now
df = pd.DataFrame(
    {
        "x": [1, 1, 2],
        "y": [1, 2, 1],
        "ImgName": [
            "png_hack/lol.png",
            "png_hack/lol2.png",
            "png_hack/lol12.png",
        ],
    }
)


p.scatter(
    y="y",
    x="x",
    source=ColumnDataSource(df),
    size=10,
)

hover = HoverTool()
hover.tooltips = """
    <div>
        <h2>Figure</h2>
        <div>
            <img src="@ImgName" alt="@ImgName" style="border:2px solid black; border-radius:20%" width="150"/>
        </div>
    </div>
"""

p.add_tools(hover)

st.title("Visualization")
st.bokeh_chart(p, use_container_width=True)

Now you will probably need to clean this folder regularly, and note that any Streamlit reinstall will purge it :wink:

Have a nice day,
Fanilo

3 Likes

Has there not been a better solution since then? This seems far from a good user experience.