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

如何将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点击事件里的正确坐标属性
  • 循环逻辑:把DataFrame的循环放在类外面,每行生成一个独立的Circle实例,符合Folium的元素添加逻辑

这样修改后,你的CSV数据就能正确传递到Jinja2模板里,实现根据每行数据生成对应样式的Circle标记了。

备注:内容来源于stack exchange,提问作者Geographos

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.23 13:12:32