Hello @blackary ,
Thank you for this component!
I’m trying to built an app that displays a grid of images.
Users can then click on any image, and then take an action that impacts the selected image.
This is my first Python app and I’ve only started learning about a month ago.
I think I narrowed the problem down to: not being able to reset the st.session_state.clicked image, but I’m not sure.
Update:
I think I can confidently confirm that somehow, the keys of past clicks on streamlit_image_coordinates() appear at rerun, even after using “del” or setting them to None.
Is there a way to disable this behavior?
I’ve updated the code:
import os
import streamlit as st
from streamlit_image_coordinates import streamlit_image_coordinates as st_ic
st.set_page_config(layout="wide")
e1, col_states, col_grid, col_select, e2 = st.columns([1, 2, 2, 1, 2], gap="small")
col_states.subheader("FIRST")
col_states.write(st.session_state)
def first_run_setup():
# Initialize st.session_state.cell_dict with default image
if "cell_dict" not in st.session_state:
st.session_state.cell_dict = {}
for row_index, row_local in enumerate(layout):
for col_index, value in enumerate(row_local):
if value == 1:
cell_key_local = f"{row_index}_{col_index}"
st.session_state.cell_dict[cell_key_local] = image_default
# Initialize st.session_state.clicked_cell with default None
if "clicked_cell" not in st.session_state:
st.session_state.clicked_cell = None
if "choice_img" not in st.session_state:
st.session_state.choice_img = None
if "first_run" not in st.session_state:
st.session_state.first_run = False
print("Finished Setup")
layout = [[0, 1, 0],
[1, 1, 1],
[0, 1, 0]]
image_list = [f"data/sprites/{f}" for f in os.listdir("../proto/data/sprites")]
image_default = "data/sprites/Empty_Module.png"
if "first_run" not in st.session_state:
first_run_setup()
# Attempt to clean image_coords from st.session_state
# This works a bit, but clicking on the same cell, results in a switch between that cell id and the highest id
# Example: If all cells are clicked, clicking cell 01 repeatedly, alternates clicked_cell between 01 and 21
if st.session_state.clicked_cell:
for idx in st.session_state.cell_dict.keys():
if st.session_state.clicked_cell == idx:
st.session_state[f"{idx}"] = None
col_states.subheader("BEFORE LOOP")
col_states.write(st.session_state)
# If any cell is clicked, store the clicked cell and reset the click
for idx in st.session_state.cell_dict.keys():
if f"{idx}" in st.session_state and st.session_state[f"{idx}"]:
st.session_state.clicked_cell = f"{idx}"
st.session_state[f"{idx}"] = None
# DELTE THE COORDS FROM EXISTENCE
for idx in st.session_state.cell_dict.keys():
if f"{idx}" in st.session_state:
del st.session_state[f"{idx}"]
col_states.subheader("AFTER LOOP")
col_states.write(st.session_state)
with col_grid:
for row_idx, row in enumerate(layout):
cells = st.columns(len(row), gap="small")
for cell_idx, cell in enumerate(cells):
if row[cell_idx] != 0:
with cell:
cell_key = f"{row_idx}_{cell_idx}"
st_ic(source=st.session_state.cell_dict[cell_key],
key=str(cell_key),
use_column_width="always")
with col_select:
if st.session_state.clicked_cell == cell_key:
st.write(f"Editing cell: {cell_key}")
col_states.subheader("AFTER CELL GEN")
col_states.write(st.session_state)
I found a solution, but i had to modify the main.js of this package and add a unix_timestamp to this function:
function clickListener(event) {
const {offsetX, offsetY} = event;
const img = document.getElementById("image");
const unixTime = Date.now();
sendValue({x: offsetX, y: offsetY, width: img.width, height: img.height, unix_time: unixTime});
}
I use the latest timestamp to identify the clicked cell.
I’m not sure if this is a good solution, but I’m also not sure exactly where to go from here.