- 数据可视化
- 数据分析
- GIS
【免费下载链接】folium
Python Data. Leaflet.js Maps.
导读
Folium 作为 Python 生态中基于 Leaflet.js 的地图可视化库,最常见的落地场景之一就是与 Flask 等 Web 框架集成,把交互式地图发布为网页服务。本文基于 docs/advanced_guide/flask.rst 官方指南及其配套示例 docs/_static/flask_example.py,系统讲解在 Flask 中嵌入 Folium 地图的三种方案:直接返回地图 HTML、以 iframe 嵌入现有页面、以及拆分地图组件(header / html / script)后手动组装。读完本文,你将能够独立搭建一个可运行的 Flask + Folium 应用,并理解每种方案背后的渲染原理与适用场景。
三种集成方案概览
官方文档明确指出:在 Flask 应用中使用 Folium 是一个常见需求,且存在多种实现方式。最简单的方式是直接返回地图的 HTML 表示;如果要把地图嵌入到已有的页面布局中,则可以选择嵌入 iframe,或者提取地图的各个组成部分(header、html、script)后手动插入页面。
这三种方式在 docs/_static/flask_example.py 中均有对应的可运行示例,分别对应三个路由:
| 路由 | 方案 | 核心调用 |
|---|---|---|
/ | 全屏渲染 | m.get_root().render() |
/iframe | iframe 嵌入 | m.get_root()._repr_html_() |
/components | 组件拆分 | header.render()/html.render()/script.render() |
运行环境只需两个 Python 包:flask与folium。启动命令为:
$ python flask_example.py启动后在浏览器访问http://127.0.0.1:5000/即可看到地图。
方案一:直接返回地图 HTML(全屏页面)
这是三种方式中最简单的一种,适用于地图本身占据整个页面的场景(如全屏可视化大屏、单一地图应用)。
from flask import Flask, render_template_string import folium app = Flask(__name__) @app.route("/") def fullscreen(): """Simple example of a fullscreen map.""" m = folium.Map() return m.get_root().render()其核心在于m.get_root()。从 Folium 的渲染模型看,每个folium.Map对象在构造时都会被挂载到一个Figure(画布)对象上——在 folium/folium.py 的Map.__init__中有明确逻辑:
Figure().add_child(self)因此get_root()返回的就是这个Figure实例,而Figure.render()会一次性产出完整的 HTML 文档(包含<head>、Leaflet 的 CSS/JS 链接、地图容器 div 以及初始化脚本)。Map类继承了JSCSSMixin(定义于 folium/elements.py),其中default_js与default_css列表(如 Leaflet 1.9.4、jQuery、Bootstrap 等资源的 CDN 链接)会在渲染时被注入到 figure 的 header 中,最终由 folium/folium.py 的JSCSSMixin.render()统一生成<script>与<link>标签。
由此可以理解该方案的特性:
- 返回的是完整、独立的 HTML 文档,浏览器直接解析即可显示地图;
- 不需要 Flask 模板引擎参与,代码最简;
- 地图尺寸默认按
folium.Map的width/height参数(默认"100%")呈现,适合整页场景。
从源码 folium/folium.py 的Map._template可以看到,页面布局相关的样式(位置、宽高、min-width/min-height、left/top)均由该模板中的header宏生成,这就是render()能输出完整页面布局的底层依据。
方案二:iframe 嵌入现有页面
当你的页面已经具备自己的导航栏、侧边栏或内容区布局,只想在地图区域嵌入一块交互地图时,iframe 是最省心的方式:地图与宿主页面互不干扰,样式完全隔离。
@app.route("/iframe") def iframe(): """Embed a map as an iframe on a page.""" m = folium.Map() # set the iframe width and height m.get_root().width = "800px" m.get_root().height = "600px" iframe = m.get_root()._repr_html_() return render_template_string( """ <!DOCTYPE html> <html> <head></head> <body> <h1>Using an iframe</h1> {{ iframe|safe }} </body> </html> """, iframe=iframe, )这里有几个关键点值得展开:
1. 尺寸控制。示例通过直接修改 figure 的属性来设定地图区域大小:
m.get_root().width = "800px" m.get_root().height = "600px"在 folium/folium.py 中,width与height参数在Map.__init__里会经过_parse_size解析成(数值, 单位)的二元组,并分别记录_width_is_percent/_height_is_percent标志;模板中据此区分使用vw/vh(百分比)还是固定像素值(同时设置min-width/min-height)。因此你也可以传入"100%"、"50%"等百分比字符串,或者直接使用folium.Map(width=800, height=600)的构造参数形式。
2._repr_html_()的作用。Map._repr_html_方法定义于 folium/folium.py:
def _repr_html_(self, **kwargs) -> str: """Displays the HTML Map in a Jupyter notebook.""" if self._parent is None: self.add_to(Figure()) self._parent: Figure out = self._parent._repr_html_(**kwargs) self._parent = None else: out = self._parent._repr_html_(**kwargs) return out它在 Jupyter 中用于地图的富文本显示,而在 Flask 场景下被"借用"来生成一段内联的 HTML 片段。这里需要特别注意:示例中调用的是m.get_root()._repr_html_()(即 figure 的_repr_html_),它返回的是包含完整<style>、<script>与地图容器 div 的自包含片段,因此可以直接塞进{{ iframe|safe }}渲染。
3. Jinja2 的安全转义。由于地图 HTML 片段包含大量<script>与<style>标签,而 Jinja2 默认会转义 HTML,模板中必须使用|safe过滤器(如{{ iframe|safe }})告知 Jinja2 这是可信的原始 HTML,否则地图将无法正常显示。
iframe 方案的优点:宿主页面结构清晰、地图样式不会污染页面其他元素;缺点:地图内外的交互隔离(如无法跨 iframe 调用地图 API),且每次请求都会额外渲染一份完整的自包含文档。
方案三:拆分地图组件(header / html / script)
这是最灵活、也是最能体现 Folium 渲染架构的方案:把地图拆解成三段独立的 HTML 片段,分别插入到宿主页面的<head>与<body>中。
@app.route("/components") def components(): """Extract map components and put those on a page.""" m = folium.Map( width=800, height=600, ) m.get_root().render() header = m.get_root().header.render() body_html = m.get_root().html.render() script = m.get_root().script.render() return render_template_string( """ <!DOCTYPE html> <html> <head> {{ header|safe }} </head> <body> <h1>Using components</h1> {{ body_html|safe }} <script> {{ script|safe }} </script> </body> </html> """, header=header, body_html=body_html, script=script, )执行顺序的意义。示例先调用m.get_root().render()再分别渲染各段,这并非冗余:Figure.render()会先遍历并渲染整棵元素树,把 Leaflet 初始化脚本、CSS/JS 资源链接、地图容器等依次写入 figure 内部的header、html、script三个子容器。从 Folium 的类继承关系可以推断(参见 folium/elements.py 与 folium/folium.py 的JSCSSMixin.render()):figure 的header会承载 Leaflet 等外部资源的<link>与<script>引用,html存放地图容器<div class="folium-map">,script存放L.map(...)等初始化 JavaScript。三段之间是严格的前置依赖——CSS 必须在 body 渲染前加载、JS 初始化脚本必须放在地图容器之后,因此示例把header放进<head>、body_html放进<body>顶部、script包进<script>标签放在最后,这一顺序是保证地图正常显示的关键。
与方案二的区别。方案二生成的 iframe 片段是"打包好"的自包含 HTML;而方案三把 CSS、DOM、JS 拆开,让你可以:
- 复用宿主页已有的头部资源(header 可按需取舍);
- 在
script前后追加自定义 JavaScript; - 将
body_html精确放置在页面任意布局位置; - 摆脱 iframe 的隔离限制,实现页面与地图的脚本级互通。
该方案代价是需要手工保证三段顺序与闭合标签正确,出错概率略高,建议封装为可复用的模板片段。
实战:搭建完整运行环境
- 安装依赖:
pip install flask folium。注意 Folium 的运行时依赖(见 requirements.txt):branca>=0.6.0(提供Figure、Element等底层元素体系)、jinja2>=2.9(模板渲染引擎)、numpy、requests与xyzservices。在 folium/init.py 中还有版本硬校验:若branca低于 0.3.0 会直接抛出ImportError。 - 保存示例:将 docs/_static/flask_example.py 完整保存为
flask_example.py(或复制到examples/目录运行)。 - 启动服务:
$ python flask_example.py示例末尾的app.run(debug=True)会以调试模式启动开发服务器,默认监听127.0.0.1:5000。浏览器分别访问:
http://127.0.0.1:5000/—— 全屏地图;http://127.0.0.1:5000/iframe—— iframe 嵌入页;http://127.0.0.1:5000/components—— 组件拆分页。
debug=True仅在开发阶段使用,生产部署(如 gunicorn、uWSGI 或平台化托管)时务必关闭调试模式,并考虑将地图渲染结果缓存,因为render()每次都会重新执行完整的模板渲染流程。
常见问题与调优建议
- 地图不显示:优先检查是否为
{{ iframe|safe }}之类的 Jinja2 变量漏加了|safe过滤器;若手写模板,再确认 header 位于<head>、script 位于地图 div 之后。 - 地图尺寸不对:通过
folium.Map(width=..., height=...)构造参数或m.get_root().width / height调整,支持像素整数与百分比字符串两种写法;模板中百分比会被渲染为vw/vh(见 folium/folium.py 的Map._template)。 - 需要多地图共存:每个
folium.Map实例都会被赋予唯一的get_name()(如map_xxxxx),即使在同一页面渲染多张地图,变量名也不会冲突,这一点从Map._template中var {{ this.get_name() }} = L.map(...)的变量命名方式可以得到验证。 - 生产环境资源加载:Folium 默认通过 CDN 加载 Leaflet 1.9.4、jQuery 等资源(见 folium/folium.py 的
_default_js/_default_css),内网或离线环境需改用add_js_link/add_css_link(定义于 folium/elements.py)替换为自建静态资源地址。
总结
Folium 与 Flask 的集成虽然入门简单,但理解其渲染模型会让你的集成方案更有章法:get_root()拿到底层Figure,render()输出完整页面,_repr_html_()生成自包含片段,header/html/script三个子容器则对应 CSS 资源、DOM 容器与初始化脚本。三种方案从"整页"到"片段"再到"组件级控制",覆盖了从最小演示到复杂布局整合的全部常见场景,官方示例 docs/_static/flask_example.py 可直接作为项目脚手架使用。
- 数据可视化
- 数据分析
- GIS
【免费下载链接】folium
Python Data. Leaflet.js Maps.
相关推荐
Dittofeed嵌入式组件:iframe集成
Dittofeed嵌入式组件:iframe集成 引言:为什么选择嵌入式集成? 在现代SaaS应用中,消息自动化已成为提升用户参与度和转化率的关键功能。Ditto
后端前端企业应用Mesop Embed 组件实战:在 Python AI 应用中安全嵌入 iframe 网页
Mesop Embed 组件实战:在 Python AI 应用中安全嵌入 iframe 网页 导读 Mesop 是面向 Python 开发者、用于快速构建 AI
前端后端Web框架react-datepicker 日历图标(CalendarIcon)组件完全指南:三种图标渲染模式与 DatePicker 集成实战
react datepicker 日历图标(CalendarIcon)组件完全指南:三种图标渲染模式与 DatePicker 集成实战 CalendarIcon
前端UI组件
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考