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

基于Dash和Leaflet实现点击地图修改GeoJSON要素属性并切换街道颜色

基于Dash和Leaflet实现点击地图修改GeoJSON要素属性并切换街道颜色

看起来你已经搞定了地图加载、街道hover变蓝这些功能,就差点击切换街道颜色这最后一步啦!别着急,我来帮你把这个功能实现~

问题分析

你的核心需求是:点击街道后,把它从透明切换为红色;再次点击可以切回透明。你已经尝试给要素加了use属性,但没成功让样式动态更新——这是因为原来的GeoJSON组件用的是静态样式,而且没有通过回调更新数据来触发样式重计算。

解决方案

我们需要做这几个关键调整:

  1. 让GeoJSON组件使用动态样式函数(你已经写了get_style_with_use,但原来的组件没用上它)
  2. 通过Dash回调,在点击时修改对应要素的use属性,然后更新GeoJSON的data属性,触发样式重新渲染
  3. 修正点击事件中获取要素ID的逻辑,正确找到要修改的街道要素

修改后的完整代码

import dash
from dash import Output, Input, State, html, no_update
import dash_leaflet as dl
import osmnx as ox
import json

# Style-Funktion für GeoJSON-Features: 未点击时透明,点击后变红
def get_style_with_use(feature):
    if feature['properties']['use'] == True:
        # 未点击状态:透明
        return {
            "color": "rgba(0,0,0,0)",
            "weight": 2,
            "opacity": 0.7,
            "fillOpacity": 0
        }
    else:
        # 点击后状态:红色
        return {
            "color": "red",
            "weight": 5,
            "opacity": 0.9,
            "fillOpacity": 0
        }

# Hover-Style (blau)
hover_style = {
    "color": "blue",
    "weight": 7,
    "opacity": 1,
    "fillOpacity": 0.5
}

# 加载德累斯顿道路网络并初始化use属性
G = ox.load_graphml("dresden_saxony_germanyroad_network.graphml")
for u, v, key, data in G.edges(keys=True, data=True):
    data['use'] = True  # 默认是未点击状态(透明)

# 转换为GeoJSON格式
geojson_data = ox.graph_to_gdfs(G, nodes=False, edges=True, fill_edge_geometry=True).to_json()
initial_data = json.loads(geojson_data)

# Dash-App 初始化
app = dash.Dash(__name__)

app.layout = html.Div([
    html.H1("Dresden Streets Map"),
    dl.Map([
        dl.TileLayer(),
        dl.GeoJSON(
            data=initial_data,
            id="geojson-dresden-streets",
            style=get_style_with_use,  # 使用动态样式函数
            hoverStyle=hover_style
        )
    ], style={'width': '1000px', 'height': '500px'}, center=[51.0504, 13.7373], zoom=12),
    html.Div(id='container-output-text', children='点击任意街道切换颜色')
])

@app.callback(
    [Output('container-output-text', 'children'),
     Output('geojson-dresden-streets', 'data')],  # 新增:更新GeoJSON数据
    Input('geojson-dresden-streets', 'n_clicks'),
    State('geojson-dresden-streets', 'clickData'),
    State('geojson-dresden-streets', 'data'),  # 传入当前的GeoJSON数据
    prevent_initial_call=True
)
def toggle_street_color(n_clicks, click_data, current_data):
    if not click_data:
        return no_update, no_update
    
    # 获取点击的街道要素ID
    clicked_id = click_data['features'][0]['id']
    # 遍历所有要素,找到对应ID的项,切换use属性
    for feature in current_data['features']:
        if feature['id'] == clicked_id:
            feature['properties']['use'] = not feature['properties']['use']
            break
    
    # 返回提示文本和更新后的GeoJSON数据
    return f"已切换街道 {clicked_id} 的颜色", current_data

if __name__ == "__main__":
    app.run(debug=True)

关键调整说明

  1. 动态样式绑定:把GeoJSON组件的style参数从静态字典改成get_style_with_use函数,这样每个要素渲染时都会调用这个函数,根据自身的use属性返回对应样式。我把你原来的绿色改成了红色,符合你“点击后变红”的需求。
  2. 回调扩展:新增了Output('geojson-dresden-streets', 'data'),这样点击后可以把修改了use属性的新数据传给GeoJSON组件,触发重新渲染。
  3. 点击事件处理:正确从clickData中提取点击要素的ID,然后遍历当前数据找到对应要素,切换use的布尔值(True↔False),实现点击切换效果。
  4. 初始状态修正:默认所有街道的use为True,对应透明状态,点击后变成False,显示红色。

现在运行代码,点击任意街道就会从透明变成红色,再次点击又切回透明,hover时还是蓝色,完全符合你的需求~

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 10:17:59