如何将CSV数据中的参数传递到Folium自定义Circle类的Jinja2宏模板中
如何将CSV数据中的参数传递到Folium自定义Circle类的Jinja2宏模板中
我看了你折腾的这几段代码,核心问题是没搞清楚自定义Folium元素的参数传递逻辑——你得把CSV里的每行数据作为实例参数传给Circle类,而不是在类内部硬循环或者直接引用外部变量。咱们一步步来修正:
1. 先理清核心逻辑
每个CSV行对应一个要创建的Circle标记,所以我们需要:
- 让自定义的
Circle类能够接收每行的参数(半径、角色、弹窗内容等) - 在Jinja2模板中通过实例属性来访问这些参数
- 遍历DataFrame,为每行生成一个
Circle实例并添加到地图
2. 修正自定义Circle类的定义
这里要注意几个关键错误:
- 之前的
{% macro script %}里的JavaScript语法错误(条件判断写法、popup设置、坐标赋值) - 类的
__init__方法不能直接引用外部的rad变量,要把参数传进来 - 实例属性要正确定义,方便模板调用
import folium from folium.elements import MacroElement from jinja2 import Template import pandas as pd # 读取CSV数据 df = pd.read_csv("survey.csv") class Circle(MacroElement): _template = Template(u""" {% macro script(this, kwargs) %} function newCircle(e){ // 创建新的Circle,而不是复用同一个实例(避免所有点击都修改同一个圆) var circle_job = L.circle(e.latlng, { radius: {{ this.radius }}, color: "{{ 'red' if this.role == 'Contractor' else 'black' }}", fillColor: "{{ 'red' if this.role == 'Contractor' else 'black' }}" }).addTo({{ this._parent.get_name() }}); // 设置弹窗内容 circle_job.bindPopup("{{ this.popup_content|safe }}"); // 把坐标赋值给页面输入框 parent.document.getElementById("latitude").value = e.latlng.lat; parent.document.getElementById("longitude").value = e.latlng.lng; circle_job.bringToFront(); }; {{ this._parent.get_name() }}.on('click', newCircle); {% endmacro %} """) # noqa def __init__(self, radius, role, popup_content): super(Circle, self).__init__() self._name = 'Circle' # 把参数存为实例属性,供模板调用 self.radius = radius self.role = role self.popup_content = popup_content
3. 遍历DataFrame生成Circle实例
现在我们可以循环处理CSV的每一行,把对应的数据传给Circle类,再添加到地图上:
# 创建基础地图 m = folium.Map(location=[df['lat'].mean(), df['lng'].mean()], zoom_start=10) # 遍历CSV每行数据 for _, row in df.iterrows(): # 整理弹窗内容 popup_content = f"<b>Phone:</b> {row['phone']}<br><b>SP:</b> {row['sp']}" # 创建Circle实例,传入当前行的参数 circle = Circle( radius=int(row['radius']), role=row['role'], popup_content=popup_content ) # 添加到地图 circle.add_to(m) # 保存地图 m.save('map.html')
关键改动说明
- 参数传递:把每行的
radius、role、popup_content作为参数传给Circle的构造函数,存为实例属性,模板里用{{ this.xxx }}就能访问 - JavaScript逻辑修复:
- 每次点击创建新的Circle实例(之前复用同一个
circle_job会导致所有点击都修改同一个圆) - 用Jinja2的条件表达式直接在模板里判断角色设置颜色
- 正确使用
bindPopup设置弹窗内容,用|safe标记弹窗内容为安全HTML - 修正坐标赋值:
e.latlng.lat和e.latlng.lng才是Leaflet点击事件里的正确坐标属性
- 每次点击创建新的Circle实例(之前复用同一个
- 循环逻辑:把DataFrame的循环放在类外面,每行生成一个独立的Circle实例,符合Folium的元素添加逻辑
这样修改后,你的CSV数据就能正确传递到Jinja2模板里,实现根据每行数据生成对应样式的Circle标记了。
备注:内容来源于stack exchange,提问作者Geographos
相关产品推荐
相关产品推荐

