如何在Streamlit-Folium中探索地图且不丢失已添加标记?
问题:Streamlit-Folium地图搜索后自定义标记消失
我用streamlit-folium在Streamlit中做地图可视化,支持用户添加自定义标记,地图设有默认起点,同时做了搜索栏让用户探索不同位置。但遇到一个问题:当搜索新位置时,之前在地图上添加的所有标记都会消失。
原始代码
import folium import streamlit as st from folium.plugins import Draw from geopy.geocoders import Nominatim from streamlit_folium import st_folium # Default location x, y = [41.00, 29.00] # Search for another location location_input = st.text_input("Search in the map") if location_input: location = Nominatim(user_agent="GetLoc") getLocation = location.geocode(location_input) x, y = getLocation.latitude, getLocation.longitude # Draw the map centered in location m = folium.Map(location=[x,y],zoom_start=12) Draw( draw_options={ 'polyline': False, 'rectangle': False, 'circle': False, 'polygon': False, 'circlemarker': False }, edit_options={'remove': False} ).add_to(m) Map = st_folium(m, width = 700, height=500)
问题原因
Streamlit的运行机制是每次用户交互(比如输入搜索内容)都会重新执行整个脚本,而你之前添加的标记没有被持久化存储,脚本重新运行时生成的是全新的空白地图,自然丢失了之前的标记。
解决方案
用Streamlit的st.session_state持久化保存用户添加的标记坐标,每次生成地图时,从会话状态中取出这些坐标重新添加到地图上。修改后的代码如下:
import folium import streamlit as st from folium.plugins import Draw from geopy.geocoders import Nominatim from streamlit_folium import st_folium from folium import Marker # 初始化会话状态,用于保存标记坐标 if 'markers' not in st.session_state: st.session_state.markers = [] # 默认位置 x, y = [41.00, 29.00] # 处理地点搜索 location_input = st.text_input("Search in the map") if location_input: location = Nominatim(user_agent="GetLoc") getLocation = location.geocode(location_input) if getLocation: # 兼容搜索不到地点的情况 x, y = getLocation.latitude, getLocation.longitude # 提取用户绘制的标记并保存到会话状态 map_data = st_folium( folium.Map(location=[x,y],zoom_start=12), width=700, height=500, returned_objects=['all_drawings'] ) if map_data.get('all_drawings'): for drawing in map_data['all_drawings']: # 仅处理点类型的标记 if drawing['geometry']['type'] == 'Point': lat = drawing['geometry']['coordinates'][1] lon = drawing['geometry']['coordinates'][0] # 避免重复添加标记(可选) if [lat, lon] not in st.session_state.markers: st.session_state.markers.append([lat, lon]) # 重新生成地图并添加所有保存的标记 m = folium.Map(location=[x,y],zoom_start=12) Draw( draw_options={ 'polyline': False, 'rectangle': False, 'circle': False, 'polygon': False, 'circlemarker': False }, edit_options={'remove': False} ).add_to(m) # 从会话状态取出标记,添加到当前地图 for marker in st.session_state.markers: Marker(location=marker).add_to(m) # 显示最终地图 st_folium(m, width=700, height=500, returned_objects=['all_drawings'])
关键修改说明
- 会话状态初始化:用
st.session_state.markers存储所有用户添加的标记坐标,确保页面刷新时数据不丢失。 - 提取绘制数据:调用
st_folium时指定returned_objects=['all_drawings'],获取用户在地图上绘制的所有元素。 - 保存新标记:遍历返回的绘制数据,提取点类型的标记坐标并添加到会话状态。
- 重新渲染标记:每次生成新地图时,从会话状态取出所有标记,重新添加到地图上。
这样无论用户搜索多少次新位置,之前添加的标记都会被保留并显示在新的地图中心位置。
内容的提问来源于stack exchange,提问作者ychiucco
相关产品推荐
相关产品推荐

