Dash应用添加folium标记后地图无法加载的问题求助
问题分析与修复方案
你的代码存在几个关键错误,导致添加标记后地图无法加载:
- Dash无法直接渲染folium对象:布局里直接放置
folium.Map(id="output-state")不符合Dash组件规则,Dash不支持直接渲染folium实例,需要将其转换为HTML组件嵌入。 - 参数传递错误:创建folium地图时,
location=['lat', 'long']和zoom_start='zoom'用了字符串字面量,而非传入的变量lat、long、zoom,这会导致地图定位到无效坐标。 - 回调输出目标错误:回调输出绑定到
folium.Map的children属性,但folium对象没有该属性,应该用html.Div承载生成的地图。
修复方案1:folium转HTML嵌入Dash
修改后的代码如下:
from dash import Dash, html, dcc, Input, Output, State import folium app = Dash() app.layout = html.Div([ html.H1(id='textout'), # 用Div承载地图,替代直接放置folium.Map html.Div(id="output-state"), dcc.Input(id='lat', value=39.298, type='number'), dcc.Input(id='long', value=-76.590, type='number'), dcc.Input(id='zoom', value=11, type='number'), html.Button('Submit', id='submit-button') ]) @app.callback(Output('output-state', 'children'), Input('submit-button', 'n_clicks'), State('lat', 'value'), State('long', 'value'), State('zoom', 'value')) def update_output(n_clicks, lat, long, zoom): if not n_clicks: # 初始状态加载默认地图 m = folium.Map(location=[39.298, -76.590], zoom_start=11) folium.Marker([39.298, -76.590], popup="You Are Here!!!").add_to(m) # 将folium地图转为HTML字符串,嵌入iframe m_html = m._repr_html_() return html.Iframe(srcDoc=m_html, width='100%', height='600px') # 使用传入的变量创建地图,而非字符串字面量 m = folium.Map(location=[lat, long], zoom_start=zoom) folium.Marker([lat, long], popup="You Are Here!!!").add_to(m) m_html = m._repr_html_() return html.Iframe(srcDoc=m_html, width='100%', height='600px') @app.callback(Output('textout', 'children'), Input('submit-button', 'n_clicks'), State('lat', 'value'), State('long', 'value'), State('zoom', 'value')) def update_text(n_clicks, lat, long, zoom): return f'纬度 {lat}, 经度 {long}, 缩放级别 {zoom}, 点击次数 {n_clicks} 次' if __name__ == '__main__': app.run_server(debug=True)
修复方案2:直接使用dash_leaflet(更适配Dash)
既然已导入dash_leaflet,推荐用原生组件实现,避免folium转HTML的额外步骤:
import dash_leaflet as dl from dash import Dash, html, dcc, Input, Output, State app = Dash() app.layout = html.Div([ html.H1(id='textout'), # 使用dash_leaflet的Map组件 dl.Map(id="output-state", style={'width': '100%', 'height': '600px'}), dcc.Input(id='lat', value=39.298, type='number'), dcc.Input(id='long', value=-76.590, type='number'), dcc.Input(id='zoom', value=11, type='number'), html.Button('Submit', id='submit-button') ]) @app.callback(Output('output-state', 'children'), Input('submit-button', 'n_clicks'), State('lat', 'value'), State('long', 'value'), State('zoom', 'value')) def update_output(n_clicks, lat, long, zoom): if not n_clicks: # 初始地图组件 return [dl.TileLayer(), dl.Marker(position=[39.298, -76.590], children=dl.Popup("You Are Here!!!"))] # 更新后的地图组件 return [ dl.TileLayer(), dl.Marker(position=[lat, long], children=dl.Popup("You Are Here!!!")) ] @app.callback(Output('output-state', 'center'), Input('submit-button', 'n_clicks'), State('lat', 'value'), State('long', 'value')) def update_map_center(n_clicks, lat, long): if not n_clicks: return [39.298, -76.590] return [lat, long] @app.callback(Output('output-state', 'zoom'), Input('submit-button', 'n_clicks'), State('zoom', 'value')) def update_map_zoom(n_clicks, zoom): if not n_clicks: return 11 return zoom @app.callback(Output('textout', 'children'), Input('submit-button', 'n_clicks'), State('lat', 'value'), State('long', 'value'), State('zoom', 'value')) def update_text(n_clicks, lat, long, zoom): return f'纬度 {lat}, 经度 {long}, 缩放级别 {zoom}, 点击次数 {n_clicks} 次' if __name__ == '__main__': app.run_server(debug=True)
关键修复说明
- 方案1通过
m._repr_html_()将folium地图转为HTML字符串,再用html.Iframe嵌入Dash,解决直接渲染folium对象的问题。 - 两种方案都修正了参数传递错误,直接使用变量而非字符串字面量。
- 方案2采用dash_leaflet原生组件,更贴合Dash的组件逻辑,无需额外HTML转换,兼容性和性能更佳。
内容的提问来源于stack exchange,提问作者rerecodes
相关产品推荐
相关产品推荐

