Custom component to display clickable images

Hi @vivien I tried your component, but it doesn’t load the images for me. I just get the “No Image Clicked” text, but clickable_images() function isn’t doing anything for me. Perhaps a package versioning issue? Can you tell if there are any minimum package requirements?

Upon further debugging, I found that paths argument is a list of urls and can’t be a list of local paths of the images currently. :+1:

Hi @therochvoices. You can provide URLs but, if your images are local files, you can also open these files, encode the images in base64, and provide “data:image/jpeg;base64,[XXX]” as paths (where [XXX] is replaced by the base64-encoded images)

1 Like

Hello @vivien

This is a very cool component! Much needed!
Is there a way currently to show the title of the image above the image as well? (Currently the title shows while hovering the mouse over the image?). Thank you!

Hi @MLbyML. Thanks. I’m afraid this isn’t possible with the component as it is now (but it shouldn’t be too complicated to do it if you want to give it a try: the javascript code to display and style the images is pretty short).

1 Like

@vivien thanks so much for sharing this, a fabulous widget which came in very handy for me today - using it to select an image when then calls an Azure image analysis service to return a description plus lists of categories, tags, landmarks, people, and brands. Love it!

1 Like

@LostGoatOnHill Thanks for the feedback. It sounds like a cool app!

@vivien you helped make this possible :slight_smile:

FYI, I created another component which is a generalization of this one: st-click-detector. It works not only on images but also on all HTML links.

Hi vivien, good day can you pls provide an exact example of this, where the image file is locally found. I am having trouble doing it. Thanks.

Hi @data.science. Here is an example:

import base64
import streamlit as st
from st_clickable_images import clickable_images

images = []
for file in ["image1.jpeg", "image2.jpeg"]:
    with open(file, "rb") as image:
        encoded = base64.b64encode(image.read()).decode()
        images.append(f"data:image/jpeg;base64,{encoded}")

clicked = clickable_images(
    images,
    titles=[f"Image #{str(i)}" for i in range(2)],
    div_style={"display": "flex", "justify-content": "center", "flex-wrap": "wrap"},
    img_style={"margin": "5px", "height": "200px"},
)

st.markdown(f"Image #{clicked} clicked" if clicked > -1 else "No image clicked")
1 Like

Hi @vivien thanks for the component, I like it. I am struggling to change the state of it though. I need a functionality which allows to state goes back to default (-1). Say I have an image which I use for saving report. I have a few more radio and dropdown lists to adjust the report page. Every time I click a radio button or dropdown list, it regenerates a report and saves it. I only want to save the report, if I click that image again. Any help appreciated, thanks.

Hi @Omer_Eker. I’d first invite you to switch to st-click-detector which is more flexible and general than st-clickable-images.

More specifically regarding the situation you describe, it might be possible to use st.session_state to keep track of the last component with which the user interacted to decide whether to trigger the saving of the report.

@vivien thanks for the reply. I tried a few workaround including using session_states but didn’t help. I am leaving a minimum reproducible example code here. Can you help me how would you do it?

import streamlit as st
from st_clickable_images import clickable_images

with st.sidebar:
    st.radio("Radio",[1,2,3])

clicked = clickable_images(
    ["https://icons.iconarchive.com/icons/custom-icon-design/pretty-office-7/256/Save-icon.png"],
    div_style={"display": "flex", "justify-content": "left", "flex-wrap": "wrap"},
    img_style={"margin": "10px", "height": "250px"},
    key="clicked_images",
)

if clicked == 0:
    st.subheader("Saving Report..")
else:
    st.subheader(f"Selected Image No: #{clicked}")

Hey @Omer_Eker. Check this out (with st-click-detector instead of st-clickable-images):

import streamlit as st
from st_click_detector import click_detector

if "n_clicks" not in st.session_state:
    st.session_state["n_clicks"] = "0"

with st.sidebar:
    choice = st.radio("Radio", [1, 2, 3])

id = str(int(st.session_state["n_clicks"]) + 1)

content = f"<a href='#' id='{id}'><img src='https://icons.iconarchive.com/icons/custom-icon-design/pretty-office-7/256/Save-icon.png'></a>"

clicked = click_detector(content, key="click_detector")

if clicked != "" and clicked != st.session_state["n_clicks"]:
    st.session_state["n_clicks"] = clicked
    st.subheader("Saving Report..")
else:
    st.subheader(f"Choice: #{choice}")
1 Like

Hi @vivien i am struggling witht the part where when i click an image i want all the remaining images to be cleared and just that 1 image be displayed. Any help on how can i achieve it.

Hi @vivien, this is a great component. Is it possible to highlight the selected image?

Thank you very much, it works fine

Hi @VishnuS-S. You should try st-click-detector which is more general and flexible.
After the component, you should record the id of the image that was clicked on in st.session so that you can use this value during the next render of the page.
I do something like this in this web app, ie remembering what was clicked on. Check out the code

1 Like

Thanks, @vivien. I’ll try it out.