ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

folium 中使用 GeoPandas GeoDataFrame 与 __geo_interface__ 渲染地图的完整指南

folium 中使用 GeoPandas GeoDataFrame 与 __geo_interface__ 渲染地图的完整指南 数据可视化数据分析GIS【免费下载链接】foliumPython Data. Leaflet.js Maps.项目地址https://gitcode.com/gh_mirrors/fo/folium点击查看免费下载导读本文基于 folium 官方用户指南geopandas_and_geo_interface.md系统讲解如何把 GeoPandas 的GeoDataFrame以及任何实现了__geo_interface__协议的对象直接渲染到 folium 地图上。你将学会用一行folium.GeoJson(gdf)完成矢量数据上图、利用GeoDataFrame的style列批量配置要素样式、以及为轨迹如 GPX 线段等非 GeoJSON 数据做坐标参考系转换后再可视化。同时结合 folium/features.py 的源码说明底层的数据处理与坐标系重投影机制帮助你避开常见的坐标轴EPSG与经纬度顺序坑。背景为什么 folium 能直接吃下 GeoDataFrameGeoPandas 是 pandas 的地理空间扩展项目核心贡献是提供了GeoDataFrame对象——它本质上就是一个“Feature Collection”GeoJSON 要素集合的表格化表示普通列存放属性geometry列存放shapely几何对象。官方指南原文指出GeoPandas is a project to add support for geographic data to pandas objects. It provides (among other cool things) aGeoDataFrameobject that represents a Feature collection.folium 之所以能与它无缝对接关键在于GeoJson图层对数据类型的宽容处理。查看 folium/features.py 中GeoJson的 docstring其data参数明确支持四类输入数据类型处理方式文件路径str读取文件内容并完整嵌入 Leaflet 的 JavaScript字典dict转换为 JSON 并嵌入 JavaScriptGeoJSON 字符串str作为 JavaScript 原样传入带__geo_interface__的对象将__geo_interface__字典序列化为 JSON若对象具备to_crs则先重投影也就是说GeoDataFrame走的是第四条路径folium 在底层把它的__geo_interface__属性由 GeoPandas 提供的 GeoJSON 描述提取出来等价于直接传入一个标准的 GeoJSON 字典。入门示例将纽约市行政区 GeoDataFrame 渲染到地图官方指南沿用了 GeoPandas 官方演示数据集——纽约市NYC五个行政区boroughs的边界数据。加载并直接渲染的核心代码只有几行import folium import geopandas boros geopandas.read_file( https://raw.githubusercontent.com/python-visualization/folium-example-data/main/new_york_boroughs.zip ) m folium.Map([40.7, -74], zoom_start10, tilescartodbpositron) folium.GeoJson(boros).add_to(m) m要点说明geopandas.read_file(...)读取 zip 中的 shapefile 并返回GeoDataFramefolium.Map([40.7, -74], ...)以纽约市市中心为地图中心zoom_start10控制初始缩放级别tilescartodbpositron选择浅色底图CartoDB Positron便于看清边界线条folium.GeoJson(boros).add_to(m)是全部核心把GeoDataFrame直接交给GeoJson图层并挂载到地图m上。从源码角度看folium.GeoJson(boros)在构造时会调用 process_data()elif hasattr(data, __geo_interface__): self.embed True if hasattr(data, to_crs): data data.to_crs(EPSG:4326) return json.loads(json.dumps(data.__geo_interface__))GeoDataFrame同时具备__geo_interface__与to_crs两个能力因此 folium 会自动把它重投影到 WGS84 经纬度坐标EPSG:4326再序列化为标准 GeoJSON 字典随后通过 features.py 中的模板以L.geoJson(...).addData(...)注入 Leaflet。这个过程对用户完全透明所以“Quite easy”。进阶用 GeoDataFrame 的 style 列批量定制样式官方指南指出可以借助GeoDataFrame自身的结构来为数据设置样式——只需新增一列style该列每个元素都是一个 CSS/Leaflet 风格字典。boros[style] [ {fillColor: #ff0000, weight: 2, color: black}, {fillColor: #00ff00, weight: 2, color: black}, {fillColor: #0000ff, weight: 2, color: black}, {fillColor: #ffff00, weight: 2, color: black}, {fillColor: #00ffff, weight: 2, color: black}, ] m folium.Map([40.7, -74], zoom_start10, tilescartodbpositron) folium.GeoJson(boros).add_to(m) m这里style列的顺序与GeoDataFrame的行一一对应五个行政区分别被填充为红、绿、蓝、黄、青五种颜色边线统一为黑色、宽度 2。常用样式键包括样式键作用示例值fillColor填充色#ff0000color边界线颜色blackweight边界线宽度像素2fillOpacity填充透明度0~10.6opacity线透明度0~11底层机制当传入的GeoJson没有显式指定style_function时folium 的模板会执行setStyle(function(feature) {return feature.properties.style;})见 features.py。GeoPandas 的__geo_interface__会把style列原样写入每个要素的properties中于是 Leaflet 直接按各要素自带的style字典着色。此外若你的 GeoDataFrame 的__geo_interface__没有正确携带列数据也可以使用style_function参数features.py 给出了官方示例style_function lambda x: { fillColor: #0000ff if x[properties][name] Alabama else #00ff00 } folium.GeoJson(geojson, style_functionstyle_function)两种方式可以按数据组织习惯任选style列适合“样式与属性同行存储”的表驱动场景style_function适合按属性动态计算样式的场景。通用协议任何带geo_interface的对象都能用GeoDataFrame只是__geo_interface__协议的一个实现者。官方指南强调folium 可以与任何实现了__geo_interface__的对象协同工作——例如 shapely 几何对象Point、LineString、Polygon 等、fiona 读取的记录等。但务必注意在把数据交给 folium 之前可能需要先转换到epsg4326因为 Leaflet 只认 WGS84 经纬度。官方示例用 fiona shapely 读取 GPX 文件中的轨迹track线段import folium import fiona import shapely url https://raw.githubusercontent.com/python-visualization/folium-example-data/main/route_farol.gpx with fiona.open(url, r, layertracks) as records: tracks [shapely.geometry.shape(record[geometry]) for record in records] track tracks[0] m folium.Map(tilescartodbpositron) folium.GeoJson(track).add_to(m) m.fit_bounds(m.get_bounds()) m这段代码展示了完整流程fiona.open(url, r, layertracks)打开 GPX 的tracks图层用shapely.geometry.shape(...)把 fiona 记录中的几何字典还原为 shapely 几何对象此例中是一条LineString轨迹取第一条轨迹tracks[0]folium.GeoJson(track).add_to(m)直接渲染 shapely 对象m.fit_bounds(m.get_bounds())让地图视野自动缩放到轨迹的包围盒范围无需手动指定中心和缩放级别。注意这里没有显式做to_crs转换是因为 GPX 规范本身就以 WGS84 经纬度存储坐标而如果你的数据来自投影坐标系如 UTM、Web Mercator EPSG:3857则应先执行track track.to_crs(4326)GeoPandas/geopandas 支持的GeoSeries.to_crs或等价转换否则地图上的位置会严重偏移。源码原理process_data 的数据分派与自动重投影综合上面两个示例GeoJson.process_data()folium/features.py是 folium 处理任意输入的“总入口”其分派逻辑可概括为if isinstance(data, dict): # 已是 GeoJSON 字典直接嵌入 elif isinstance(data, str): if data 以 http/https/ftp 开头: # 远程 URL if not self.embed: self.embed_link data return self.get_geojson_from_web(data) # requests.get(url).json() elif data 以 [ 或 { 开头: # 内联 GeoJSON 字符串 return json.loads(data) else: # 本地文件名 if not self.embed: self.embed_link data return json.loads(open(data).read()) elif hasattr(data, __geo_interface__): self.embed True if hasattr(data, to_crs): data data.to_crs(EPSG:4326) # 关键自动重投影到 WGS84 return json.loads(json.dumps(data.__geo_interface__)) else: raise ValueError(Cannot render objects with any missing geometries)几个值得注意的工程细节自动重投影的触发条件只有同时具备__geo_interface__和to_crs方法的对象正是GeoDataFrame/GeoSeries才会被自动转换到EPSG:4326普通 shapely 对象没有to_crs所以需要用户自行保证坐标已是经纬度这印证了官方指南中“有时你可能需要先将数据转换到 epsg4326的提醒。embed 开关带__geo_interface__的对象一律强制embed True即数据完整序列化后内嵌进 HTMLembedFalse只对提供文件链接或 URL 的输入生效见 features.py。要素标识当使用了style_function/highlight_function时folium 会调用 convert_to_feature_collection() 确保数据是 FeatureCollection并通过 find_identifier() 为每个要素生成唯一id再基于 id 构建样式映射style_map在 JavaScript 中以switch语句按feature_identifier分发样式见 features.py。这与“style 列”机制并行存在模板中if not this.style分支即处理无style_function时读取feature.properties.style的场景。样式列丢失的风险若你在style_function模式下自定义样式而 GeoDataFrame 恰好也有style列模板的setStyle兜底逻辑不会触发因为this.style为真请以style_function的返回值为准。仓库中的测试也印证了这套机制例如 tests/test_folium.py 中的test_choropleth_geopandas_numeric通过gpd.GeoDataFrame.from_features(...)构造 GeoDataFrame 并set_crs(epsg:4326)后交给Choropleth其底层同样是GeoJson验证了属性列与几何的联动tests/snapshots/modules/issue_2109.py 展示了用gpd.points_from_xy从经纬度 DataFrame 构造GeoDataFrame(crsEPSG:4326, geometry...)的常见实战模式。常见问题与最佳实践1. 坐标参考系CRS不一致导致位置错乱症状要素显示在地球另一侧、比例失真或完全不可见。原因数据不是 WGS84 经纬度如 EPSG:3857 Web Mercator、UTM 等。对策交数据前统一执行gdf gdf.to_crs(EPSG:4326)仅当数据源保证为经纬度如 GPX时才可跳过。2. GeoDataFrame 列没有进入 properties若你的样式/属性未出现在前端检查gdf.__geo_interface__[features][0][properties]是否包含目标列GeoPandas 序列化时默认只带非几何列若使用自定义索引可能需要在read_file后重置索引reset_index()确保属性完整。3. 大数据集性能GeoJson默认将全部数据内嵌进 HTMLembedTrue数据集过大时 HTML 会膨胀。可考虑先用gdf.geometry.simplify(...)简化几何仓库快照示例 tests/snapshots/modules/issue_1989.py 即用simplify(0.05)处理后再渲染或改用 MarkerCluster、vectorgrid_protobuf 等插件按需加载。4. 与 Leaflet 的经纬度顺序差异GeoJSON 规范要求坐标顺序为[经度, 纬度]而 Leaflet 的L.latLng是[纬度, 经度]。folium 已按 GeoJSON 惯例处理__geo_interface__序列化结果用户只需保证Map([lat, lon])中心点参数为[纬度, 经度]即可参考 coordinate_ordering.md。小结folium 之所以能与 GeoPandas 生态无缝协作靠的是GeoJson图层对__geo_interface__协议的内建支持process_data() 会自动提取GeoDataFrame/GeoSeries/ shapely 对象的 GeoJSON 描述并在对象提供to_crs时自动重投影到 EPSG:4326。在此基础上你既可以直接把整个GeoDataFrame丢给folium.GeoJson(...)快速出图也可以利用style列或style_function精细控制每个要素的样式还能把 fiona shapely 读出的任意几何如 GPX 轨迹直接上图并配合fit_bounds自动取景。只要记住“坐标先转 WGS84、属性列要保留在 properties 中”这两条原则从 DataFrame 到交互式 Leaflet 地图只需一行代码的距离。延伸阅读GeoJSON 图层基础用法加载文件、URL、字符串与 dictGeoJSON 要素级 tooltip / popup 定制基于 GeoDataFrame 的 Choropleth 专题图GeoJSON 与 Leaflet 坐标顺序差异GeoJson 核心实现源码赞分享数据可视化数据分析GIS【免费下载链接】foliumPython Data. Leaflet.js Maps.项目地址https://gitcode.com/gh_mirrors/fo/folium点击查看免费下载相关推荐Folium地图渲染引擎完全指南从Python数据到交互式地图的魔法转换Folium地图渲染引擎完全指南从Python数据到交互式地图的魔法转换 想要将Python数据变成精美的交互式地图吗 Folium地图渲染引擎正是你需数据可视化数据分析GISPython OBD入门到实战5步搭起你的车载数据监控系统Python OBD入门到实战5步搭起你的车载数据监控系统 Python OBD 是一个用于读取 OBD II 车辆数据的开源串口模块只要配上一个几十块钱的物联网智能硬件在Python中使用Falcor图形渲染框架的完整指南在Python中使用Falcor图形渲染框架的完整指南 引言当实时渲染遇见Python生态 还在为复杂的图形渲染API而头疼想要将强大的实时渲染能力与Pyt图形学深度学习上一篇三步开始资源下载res-downloader 本地代理与无水印视频抓取全解下一篇Nightingale 监控 NSQ基于 Categraf 的 nsq 采集器配置、指标释义与告警实战创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表