You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Python Streamlit-Folium地图中点击弹窗后获取坐标?

问题分析与解决方案

你的核心问题在于前端JavaScript无法直接调用后端Python函数传递数据——Folium的JS代码运行在浏览器中,而Python代码运行在Streamlit服务器环境,两者没有直接的函数调用通道,这就是你遇到result未定义错误的根本原因。

下面提供两种可行的实现方案,根据你的需求选择:


方案一:利用st_folium内置交互(最简便)

如果不需要弹窗按钮触发,直接点击标记即可获取坐标并关联DataFrame数据,st_folium本身会返回用户的交互信息:

import folium
import streamlit as st
from streamlit_folium import st_folium
import pandas as pd

# 初始化地图
map = folium.Map(location=[38,-96.5], zoom_start=4)
df.reset_index(drop=True,inplace=True)
cords = df[["lat","lon"]].values.tolist()

# 添加所有标记
for i in range(df.shape[0]):
    row = df.iloc[i]
    popup_content = f"""
    {row["name"]}<br>
    {row["date"]}<br>
    {row["city"]}, {row["state"]}
    """
    folium.Marker(cords[i], popup=folium.Popup(popup_content, max_width=300)).add_to(map)

# 渲染地图并获取交互数据
i_map = st_folium(map, width=700, height=450)

# 处理点击事件
if i_map.get("last_object_clicked"):
    # 获取点击标记的坐标
    lat = i_map["last_object_clicked"]["lat"]
    lon = i_map["last_object_clicked"]["lng"]
    st.write("选中的坐标:", (lat, lon))
    
    # 匹配DataFrame中的对应数据
    selected_row = df[(df["lat"] == lat) & (df["lon"] == lon)]
    if not selected_row.empty:
        st.write("该位置详细信息:")
        st.dataframe(selected_row)

方案二:弹窗按钮触发坐标传递(满足你的原始需求)

如果必须通过弹窗内的按钮触发,需要通过前端JS将坐标传递到Streamlit的会话状态(session_state),实现前后端数据同步:

import folium
import streamlit as st
from streamlit_folium import st_folium
import pandas as pd
import jinja2

# 初始化会话状态,存储选中的坐标
if "selected_coords" not in st.session_state:
    st.session_state.selected_coords = None

map = folium.Map(location=[38,-96.5], zoom_start=4)
df.reset_index(drop=True,inplace=True)
cords = df[["lat","lon"]].values.tolist()

for i in range(df.shape[0]):
    row = df.iloc[i]
    # 给每个弹窗的输入框设置唯一ID,避免多个标记冲突
    popup_content = f"""
    <input type="text" value="{cords[i][0]}, {cords[i][1]}" id="location-{i}" readonly> <br>
    {row["name"]}<br>
    {row["date"]}<br>
    {row["city"]}, {row["state"]}<br>
    <button onclick="sendCoords({i})">Show More</button>
    """
    folium.Marker(cords[i], popup=folium.Popup(popup_content, max_width=300)).add_to(map)

# 添加JS脚本,将坐标发送到Streamlit会话状态
el = folium.MacroElement().add_to(map)
el._template = jinja2.Template("""
    {% macro script(this, kwargs) %}
    function sendCoords(index) {
      // 获取当前标记的坐标
      var coordInput = document.getElementById("location-" + index);
      var coords = coordInput.value.trim();
      
      // 发送坐标到Streamlit会话状态
      window.parent.postMessage({
        type: 'streamlit:setSessionState',
        key: 'selected_coords',
        value: coords
      }, '*');
    }
    {% endmacro %}
""")

# 渲染地图
i_map = st_folium(map, width=700, height=450)

# 展示选中的坐标及对应数据
if st.session_state.selected_coords:
    st.write("选中的坐标:", st.session_state.selected_coords)
    # 解析坐标字符串为浮点数
    lat, lon = [float(x.strip()) for x in st.session_state.selected_coords.split(",")]
    # 匹配DataFrame数据
    selected_row = df[(df["lat"] == lat) & (df["lon"] == lon)]
    if not selected_row.empty:
        st.write("该位置详细信息:")
        st.dataframe(selected_row)

关键注意点

  1. 避免ID冲突:多个标记的弹窗输入框必须设置唯一ID,否则JS会获取错误的坐标值。
  2. 会话状态同步:通过window.parent.postMessage实现前端JS与后端Python的会话状态同步,这是Streamlit中前后端数据交互的标准方式。
  3. 坐标解析:处理坐标字符串时要注意去除空格,避免转换浮点数时出错。

内容的提问来源于stack exchange,提问作者Kyle Chitty23

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 03:09:57