streamlit-folium
streamlit-folium copied to clipboard
How can I mange the features of a drawn layer in the session state?
I'm trying to make it so that when I draw multiple polygons with the Draw plugin, I can store them in an array of features in the session state. I want to make it so that I can add features to it, delete them, etc. so that I can also attach a small form to each one which can be submitted to a backend.
However, whenever I add a feature, the only thing I seem to get is the last active drawing and the "all drawings" list. There is no unique identifier per feature.
Clicking on a drawn feature also seems to only return the last active drawing.
Deleting features will also just return a dict of enumerated feature objects, but the count will start over from 0 and not exclude the one that was deleted.
Is it even possible to do this? I just want to be able to manage a group of polygons and have each of them get a new identifier upon creation that I can then refer back to.
This my my code so far:
import streamlit as st
from streamlit_folium import st_folium
import folium
from folium.plugins import Draw
import json
st.set_page_config(layout="wide")
m = folium.Map(location=[0, 0], zoom_start=1, tiles='OpenStreetMap')
# folium.LayerControl().add_to(m)
my_feature_group = folium.FeatureGroup(name="my_feature_group")
my_feature_group.add_to(m)
my_draw_control = Draw(edit_options={ "featureGroup": "my_feature_group", })
my_draw_control.add_to(m)
c1, c2 = st.columns(2)
with c1:
output = st_folium(m, width=700, height=500, returned_objects=["last_active_drawing", "all_drawings"])
st.session_state["feature_storage"] = output["all_drawings"]
st.session_state["last_active_drawing"] = output["last_active_drawing"]
with c2:
st.write("feature_storage:")
if st.session_state["feature_storage"]:
st.write(st.session_state["feature_storage"])
st.write("last_active_drawing:")
if st.session_state["last_active_drawing"]:
st.write(st.session_state["last_active_drawing"])
I don't know the answer off-hand, but it's an interesting dilemma...my gut reaction is that streamlit-folium doesn't have a good way to add labels (since you're talking about a Folium plugin), but at the same time, it feels like this should be programmatically possible.
I wonder if there is a side solution where you use something a collapsible window to display the entire list of shapes passed back by all_drawings, use Shapely or something to give a small reference image, then use that table to add labels to the drawings.
In 2024 we implemented javascript event handlers on Folium maps. (I am one of the contributing developers of Folium). One direction you could explore is to intercept the "draw:created" event and add a unique id property to the feature. A short example:
import folium
import streamlit as st
from folium.plugins import Draw
from streamlit_folium import st_folium
m = folium.Map(location=[39.949610, -75.150282], zoom_start=5)
Draw(export=False).add_to(m)
on_create = folium.JsCode("""
(e) => {
// Generate an id for the feature
var feature = (e.layer.feature = e.layer.feature || {})
feature.type = "Feature"
feature.properties = feature.properties || {}
feature.properties["id"] = Date.now();
}
""")
handlers = {
"draw:created": on_create,
}
m.on(**handlers)
c1, c2 = st.columns(2)
with c1:
result = st_folium(m, width=700, height=500)
with c2:
st.write(result)
I don't have the context to validate the answer, but I trust @hansthen is correct above. If not, I'll re-open this issue