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

如何在dash-leaflet的app.callback中配置hover_feature、click_feature的多输入输出

Dash-leaflet 多回调冲突解决方案

问题根源

冲突本质是Dash框架的核心限制:同一个组件的同一个属性,不允许被多个回调函数同时作为输出目标绑定。你原有代码中layer组件的children属性同时被点击标记回调、悬浮高亮回调两个函数绑定,因此二者无法同时生效。

最优解决方案:拆分独立图层

最简单的适配方式是将不同功能的图层拆分,分别绑定独立的输出目标,完全规避属性冲突:

第一步:修改Layout结构

把原来的单一LayerGroup拆分为两个,分别存放点击生成的标记、悬浮高亮的多边形:

app.layout = html.Div(children=[
    dl.Map(children=[
        dl.TileLayer(),
        # 拆分图层:专门存放点击生成的标记
        dl.LayerGroup(id="marker-layer"),
        # 拆分图层:专门存放悬浮高亮的多边形
        dl.LayerGroup(id="highlight-layer"),
        dl.GeoJSON(
            url='https://pkgstore.datahub.io/core/geo-countries/countries/archive/23f420f929e0e09c39d916b8aaa166fb/countries.geojson', 
            id="countries",
            options=dict(style=dict(opacity=0,fillOpacity=0)),
            hoverStyle=arrow_function(dict(weight=2, color='red', dashArray='', opacity=1))
        )
    ],
    style={'width': '1000px', 'height': '500px'}, zoom=3, id='map'),
    html.Div(id='country'),
    html.Div(id='Country info pane')
])

第二步:调整回调绑定对应输出

将不同功能的回调输出绑定到对应的拆分图层,无需修改原有业务逻辑:

# 点击地图放置标记的回调,输出到标记专属图层
@app.callback(
    Output("marker-layer", "children"), 
    Input("countries", "click_feature"),
    prevent_initial_call=True
)
def map_click(feature):
    return [dl.Marker(position=[np.random.randint(-90,90),np.random.randint(-185,185)])]

# 悬浮国家的回调,同时输出信息面板、高亮多边形到专属图层
@app.callback(
    Output('Country info pane', 'children'),
    Output('highlight-layer', 'children'),
    Input('countries', 'hover_feature'),
    prevent_initial_call=True
)
def country_hover(feature):
    if feature is None:
        # 悬浮离开区域时清空内容
        return "", []
    country_id = feature['properties']['ISO_A3']
    return country_id, [dl.Polygon(positions=[[30,40],[50,60]], color='#ff002d', opacity=0.2)]

备选方案:单回调多触发源

如果不想拆分图层,可以将两个触发源合并到同一个回调,通过回调上下文判断触发事件,合并输出图层内容:

# 引入回调上下文
from dash import callback_context

@app.callback(
    Output('Country info pane', 'children'),
    Output('layer', 'children'),
    Input('countries', 'hover_feature'),
    Input("countries", "click_feature"),
    prevent_initial_call=True
)
def handle_all_events(hover_feature, click_feature):
    # 初始化图层内容列表
    layer_content = []
    info_content = ""
    # 获取触发源
    trigger = callback_context.triggered[0]['prop_id']
    
    # 处理悬浮事件
    if trigger == 'countries.hover_feature' and hover_feature is not None:
        info_content = hover_feature['properties']['ISO_A3']
        layer_content.append(dl.Polygon(positions=[[30,40],[50,60]], color='#ff002d', opacity=0.2))
    # 处理点击事件
    if trigger == 'countries.click_feature':
        layer_content.append(dl.Marker(position=[np.random.randint(-90,90),np.random.randint(-185,185)]))
    
    return info_content, layer_content

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 02:06:04