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

如何实现Folium中Marker悬停/点击时显示对应Circle?

实现Folium Marker悬停/点击时显示对应Circle的方案

问题描述

希望仅在Folium的Marker被悬停(hover)或点击时,显示对应的Circle。尝试结合tooltip或popup实现但未生效,第二段代码中所有Circle默认显示导致互相重叠,需要可行的实现方法。

解决方案

Folium本身没有直接提供Marker与Circle关联交互的API,需要借助Leaflet的原生JavaScript事件来控制Circle的显示隐藏。核心思路是:默认隐藏所有Circle,通过绑定Marker的鼠标事件触发对应Circle的显示/隐藏。

完整实现代码

import folium
import pandas as pd

# 读取数据
df = pd.read_csv("survey.csv")

# 初始化地图
m = folium.Map(
    location=[df['lat'].mean(), df['lng'].mean()],
    zoom_start=10
)
feature_group = folium.FeatureGroup(name="Surveyors")

# 循环创建Marker和Circle
for idx, row in df.iterrows():
    lat = row['lat']
    lng = row['lng']
    sp = row['sp']
    phone = row['phone']
    popup_content = f'<b>Phone: </b>{str(phone)}'
    
    # 创建Marker,添加自定义data-id用于关联Circle
    marker = folium.Marker(
        location=[lat, lng],
        tooltip='<strong>Contact surveyor</strong>',
        popup=folium.Popup(popup_content, max_width=300),
        icon=folium.Icon(color='black', icon='glyphicon-user')
    )
    # 给Marker添加自定义属性标记
    marker.add_child(folium.Element(f'<div data-marker-id="{idx}" class="survey-marker"></div>'))
    feature_group.add_child(marker)
    
    # 创建Circle,默认隐藏,添加相同的关联ID
    circle = folium.Circle(
        location=[lat, lng],
        radius=32186,  # 20英里换算为米
        popup=sp,
        tooltip=f'{sp} - Job limits',
        color='#1565C0',
        fill=True,
        fill_color='#42A5F5',
        opacity=0,  # 默认完全透明隐藏
        fill_opacity=0,
        class_name='survey-circle'
    )
    circle.add_child(folium.Element(f'<div data-circle-id="{idx}"></div>'))
    feature_group.add_child(circle)

m.add_child(feature_group)

# 添加自定义JavaScript控制交互逻辑
custom_js = """
<script>
document.addEventListener('DOMContentLoaded', function() {
    // 获取所有标记了survey-marker的元素
    const markerElements = document.querySelectorAll('.survey-marker');
    
    markerElements.forEach(markerEl => {
        const markerId = markerEl.getAttribute('data-marker-id');
        // 找到对应ID的Circle元素(Leaflet中Circle对应DOM的path元素)
        const circleEl = document.querySelector(`.survey-circle [data-circle-id="${markerId}"]`).closest('.leaflet-interactive');
        
        // 获取Marker的DOM节点(Leaflet的Marker图标元素)
        const markerIcon = markerEl.closest('.leaflet-marker-icon');
        
        // 悬停显示Circle
        markerIcon.addEventListener('mouseover', function() {
            circleEl.style.opacity = '0.2';
            circleEl.style.fillOpacity = '0.25';
        });
        
        // 离开隐藏Circle
        markerIcon.addEventListener('mouseout', function() {
            circleEl.style.opacity = '0';
            circleEl.style.fillOpacity = '0';
        });
        
        // 点击切换Circle显示状态(可选功能)
        markerIcon.addEventListener('click', function() {
            const currentOpacity = circleEl.style.opacity;
            if (currentOpacity === '0' || currentOpacity === '') {
                circleEl.style.opacity = '0.2';
                circleEl.style.fillOpacity = '0.25';
            } else {
                circleEl.style.opacity = '0';
                circleEl.style.fillOpacity = '0';
            }
        });
    });
});
</script>
"""

# 将自定义JS注入地图
m.get_root().html.add_child(folium.Element(custom_js))

# 保存地图
m.save('survey_interactive_map.html')

关键说明

  1. 关联Marker与Circle:通过给两者添加相同的data-id属性,确保能准确找到对应关系。
  2. 默认隐藏Circle:初始化Circle时设置opacity=0和fill_opacity=0,让它默认不可见。
  3. JavaScript事件绑定:监听Marker的mouseover、mouseout和click事件,动态修改对应Circle的透明度,实现显示/隐藏切换。
  4. Leaflet DOM结构适配:通过closest()方法定位到Leaflet生成的Circle交互元素,确保样式修改生效。

为什么之前的方法无效?

  • Folium的tooltip和popup仅支持显示文本或HTML内容,无法直接控制其他图层的显示状态。
  • 第二段代码直接添加所有Circle,未做隐藏处理,导致所有Circle默认显示并重叠。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 23:55:18