☰
用电路理论识别生态廊道:Circuitscape 实战指南
2026/10/23 11:33:23 网站建设 项目流程

简介:Circuitscape软件包集.zip是一套基于电路理论进行生态连通性分析的工具集合,面向生态学者、保护生物学研究者与国土空间规划人员,解决栖息地破碎化背景下的廊道识别与障碍评估问题。包内不仅包含Circuitscape核心程序,还集成了Linkage Mapper、Pinchpoint Mapper与Barriers Mapper三款主流插件,分别用于生态廊道生成、瓶颈区(掐点)定位及阻隔障碍量化,可支撑从数据预处理到结果制图的完整分析流程。整个压缩包共264个文件,以Python脚本(py)、ArcGIS geodatabase数据(gdb、gdbtable)、矢量图层(shp)、地图文档(mxd)及说明文档(pdf、docx)为主,同时包含栅格辅助文件(adf、img),约95.49MB,目录结构清晰,便于直接加载到ArcGIS环境中使用。目前已有2609人学习下载,适合需要开展物种连通性建模、保护区规划或生态网络评估的科研人员与规划师使用。

1. 生态廊道识别,为什么我换回了电路理论

以前做生态廊道分析,团队默认用最小成本路径,一次给出一条带状通道。等我把结果铺到现场地图上才发现,那条“最优路径”穿过村庄、绕开林地,像一根线把保护区串起来,而不是一片生物真正会走的区域。后来在一次物种扩散模拟的复盘里,我们把某山地生态廊道项目的数据换成 Circuitscape 重新分析,电流密度图把几条潜在的绕行路径都照出来了,这才明白电路理论比最短路径更贴近物种“随机游走+多路径”的真实扩散方式。

Circuitscape 就是拿电路理论算景观连通性的工具:把阻力面当电阻栅格、把目标斑块当电极,求解电流密度和电压。电流密度高的区域就是生物最可能穿过的“热区”。适合做野生动物廊道规划、道路阻隔评估、城市绿地网络构建的研究人员和规划从业者。它最反直觉的一点在于:高阻力但不完全断开的区域,反而可能因为“绕行瓶颈”被电流集中放大——这是最小成本路径永远给不出的视角。

2. 电路理论基础与输入输出:别急着跑,先搞清楚它在算什么

2.1 把景观变成电路:节点、电阻与电流密度

电路理论应用到景观连通性,核心是三个概念:节点、电阻栅格、电流密度。阻力面里的每个栅格被看作一个电阻单元,阻力值越高代表通过难度越大,电流到达的阻力就越大。我们要分析的目标斑块,比如两片保护区,被设置为节点(电极),在 Circuitscape 里叫作 focal node。电流从正极节点注入,从负极节点流出。理论前提是假设物种在景观中扩散像一个“随机游走者”,不断选择阻力较低的方向移动,整体行为接近电荷在导体网络中寻找低电阻通道的规律。

输出中最重要的是电流密度图。电流密度高的栅格,并不一定在“阻力最低路径”上,而更可能出现在“多条可用路径交汇的瓶颈处”。我在实际项目里见过一个例子:一片阻力面里有一条阻力值偏高的山脊,但它是两侧湿地的唯一连接点,电流密度在那里被压得很高。“高阻力等于没用的走廊”这个直觉在这里完全不成立,这正是 Circuitscape 相对最小成本路径最有价值的地方。

从计算原理看,Circuitscape 把每个节点对看作一个电源和地之间的电路,利用稀疏矩阵求解节点电压。对每一对节点解一次方程,所以节点对越多、栅格网越细,计算量越大。理解这一点很重要——后面设置参数和预测时间都要回到这里。

2.2 运行模式怎么选:Pairwise、One-to-all 和 Advanced

Circuitscape 提供几种连接方案,得先弄明白再选。我刚上手时直接跑默认模式,结果输出一堆看不懂的文件,后来才发现选错了连接类型。

最常见的 Pairwise(两两节点)模式,会对每一对节点分别求解,生成每对节点单独的电流密度图。这种模式适合节点少、想单独观察两片栖息地之间廊道的场景。One-to-all 模式则把每个节点分别与其余所有节点连接,输出每个节点到整体的连接累积图,适合评估单一重要节点对整个网络的贡献。

Advanced 模式用来做中心性分析和特殊配置,比如指定 ground 节点,或者想在多个节点之间共享电流来源。如果只是常规廊道识别,先从 Pairwise 开始。软件包里带的文档对四种模式有示意和参数表格,强烈建议第一次跑之前通读一遍——模式选错,后面所有解读都会偏。

除了连接模式,还要理解“接地节点”。电路理论里电流必须从正极流向接地端,Circuitscape 也需要一个 ground 节点来控制电压参考点。通常指定其中一个目标斑块作为 ground,另一组作为 source。如果你有多个 source 和一个共同的 target,就非常适合用 Advanced 模式里的“多源单地”设置。

2.3 输入输出文件家族:从 .asc、.csv 到电流密度结果

Circuitscape 的输入文件类型很固定:阻力栅格是 ASCII 网格格式(.asc),节点是 CSV 或 TIF。ASCII 网格是很多 GIS 工具的通用交换格式,头部保存行列数、角点坐标、像元大小和 NoData 值。节点文件则记录每个节点的坐标或行列号,程序靠它把节点映射到栅格上。

输出文件常见的有电流密度图 current density map、电压图 voltage map,以及区分来源方向的当前流图。格式默认是 .asc,也可以设置输出 .tif。项目里我会把电流密度图继续转到 GIS 里做密度分级,配合栖息地数据做叠加分析。

有一件事容易被忽略:输出分辨率默认和阻力栅格一致,但如果计算网格配置选择“创建新的计算网格”,程序会尝试用更粗的网格节省内存,这时候就要留意文件头部的行列数变化。我的习惯是保持原始分辨率输出,避免后期做重采样引入误差。

3. 数据准备实战:从阻力面到 Circuitscape 能读的文件

3.1 阻力面的规范化:重分类、坐标系与 NoData 三件套

阻力面是整个分析里最主观又最影响结果的部分。它通常来自土地利用类型重分类,比如林地阻力值给 1,农田给 10,城镇给 100。这里最需要注意一个误区:阻力值的跨度不要拉太大。我见过有人把水体设为 1000,把道路设为 1,结果高阻力栅格在电路里基本等于绝缘体,电流全被逼到低阻力窄带上,输出的廊道图变成沿公路的一条细线,明显不符合实际。

我一般的做法是把所有类型映射到 1~100 的区间,且保证相邻类型之间的差值不要超过一个数量级。这样既保留了不同景观类型的通过性差异,又不会让电路被个别栅格主导。实现重分类可以用 GIS 软件手工做,也可以用表格驱动的方式,把类型编码和阻力对应关系写成一个 CSV,再按属性表字段映射过去。

坐标系和分辨率必须统一。阻力栅格、节点坐标、掩膜栅格如果坐标系不一致,程序不会报错,但输出会在错误的位置上,而且非常难排查。在做数据准备时我习惯把所有图层统一到一个投影坐标系,同时检查像元大小是否一致。如果两片区域数据来自不同来源,分辨率不同,优先用较细的一方重采样到统一分辨率。

NoData 的处理在 Circuitscape 里有特殊性。程序会把 NoData 区域当成完全绝缘、电流无法通过的地方。若用 ArcGIS 的栅格计算器导出 ASCII,默认 NoData 值可能很大或为 0,你需要明确知道你的 NoData 用了什么值。有一类常见问题是,NoData 区域被错误赋成一个很大的数,比如 9999,本意是“不参与计算”,结果因为阻力值过高,把整个区域变成了电路的断路区——如果 NoData 包围了目标节点,电流就永远流不过去。

提示:把所有涉及分析的栅格在 GIS 里先“裁剪+掩膜”到同一研究范围,再导出 ASCII。不要靠 ASCII 文件头手动裁剪边界,实测非常容易翻车。

3.2 把栅格导出成 ASCII:用 GDAL 命令行一次搞定

Circuitscape 读取的是 ESRI ASCII Grid 格式。最常见导出手段是 GDAL 的 gdal_translate,命令简单,而且不会像某些 GIS 软件在导出时偷偷改 NoData 值。下面这段命令把 GeoTIFF 阻力面转成 ASCII:

gdal_translate -of AAIGrid -ot Float32 -a_nodata -9999 input_resistance.tif resistance.asc
  • -of AAIGrid指定输出为 ESRI ASCII Grid。
  • -ot Float32设置输出数据类型为单精度浮点,避免整数栅格在转换时丢失阻力值的精度。
  • -a_nodata -9999强制指定输出文件的 NoData 标识为 -9999。这个值要跟后面所有相关配置保持一致。

转换完成后,用文本编辑器打开 .asc 文件抽查前几行。头部信息类似ncols 1200、nrows 900、xllcorner 400000、yllcorner 3300000、cellsize 30、NODATA_value -9999。记得检查NODATA_value是不是你指定的 -9999,以及角点坐标是否和原始数据一致。我每次转换后都会用 GIS 软件重新加载一次 .asc,确认栅格位置没有发生整体偏移。

3.3 节点文件的格式:坐标还是行列号?

节点文件是 CSV,记录所有要分析的目标斑块位置。最简单的是三列:id,x,y或id,row,col。用坐标时,坐标系必须和阻力栅格完全一致。用行列号时,要理解它从左上角起算,第 0 行、第 0 列对应第一个栅格单元。

我习惯用坐标方式,因为可以在 GIS 里直接从保护区斑块边界提取中心坐标,不用手工数行列号。生成节点文件可以写一个小脚本,把斑块质心坐标输出成 CSV:

import csv import geopandas as gpd patches = gpd.read_file("target_patches.shp") centroids = patches.geometry.centroid with open("nodes.csv", "w", newline="") as f: writer = csv.writer(f) writer.writerow(["id", "x", "y"]) for idx, point in enumerate(centroids, start=1): writer.writerow([idx, point.x, point.y])

这段脚本使用 GeoPandas 读取目标斑块面文件,然后求每个面的质心,最终写出 Circuitscape 需要的节点表。需要注意两点:一是面要素必须是单部件,多部件面计算质心会偏;二是质心点有可能落在 NoData 或高阻力栅格上,如果落在 NoData 区域,程序会直接忽略该节点,导致电流密度图缺失。稳妥的做法是在导出节点文件后,在 GIS 里叠加阻力面逐点检查,把落在无效区域的节点手动移到最近的像元。

注意:节点数量直接决定计算量。10 个节点两两配对是 45 对,50 个节点是 1225 对。如果只是为了识别主廊道,先少选几个关键斑块,跑通流程后再慢慢加节点。

4. 参数设置与命令行运行:从图形界面到批量执行

4.1 图形界面跑通第一遍:连接方案与输出开关怎么设

第一次运行我建议打开 Circuitscape 的图形界面,把输入输出路径填好,先用两个节点跑通。界面里需要设置的项不多,但每一项都直接影响输出是否可用。

需要依次指定阻力栅格路径、节点文件路径、输出文件前缀。连接方案选择 Pairwise(两两节点)。在输出选项里,同时打开“写电流密度图”和“写电压图”,格式可以在 ASCII 和 GeoTIFF 之间选,建议第一步选 ASCII,方便后续检查头部信息。

高级选项里有个“保留面积权重”和“连接方案”等设置,保持默认即可。真正需要注意的,是界面下方的“扫描整个景观”或者计算网格相关选项。如果计算区域很大,程序默认会尝试对阻力面进行网格粗化,即把多个像元合并成一个大像元,以节省内存。对新手,这个选项建议关闭或保持原始分辨率,因为粗化后的电流密度图会出现失真,后续再分析会误导。

跑完一对节点后,检查输出目录里是不是生成了两个主要文件:一个是 current density 栅格、一个是 voltage 栅格。用 GIS 加载 current 栅格,看电流是否集中在预期方向。如果电流图全黑或全白,八成是节点文件或 NoData 出了问题,赶紧回上一章检查数据。

4.2 用配置文件生成脚本:参数的可复现关键

图形界面点几次很直观,但参数藏在内存里,没法复现。第二次以后我全部改用配置文件方式,因为廊道分析通常要做多组阻力面、多组节点对比,命令行方式能自动循环跑几十组数据。

Circuitscape 的配置沿用 INI 格式,下面这段脚本生成一组标准配置:

config_text = """ [Options for advanced mode] ground_file = (none) habitat_file = (none) [Output options] write_curr_maps = true write_volt_maps = true output_file = outputs/mountain_corridor_current output_format = asc [Calculation options] low_memory_mode = false parallelize = 4 [Input options] habitat_file = inputs/nodes.csv point_file = inputs/nodes.csv resistance_file = inputs/resistance.asc [Connection scheme] connect_scheme = pairwise [Logging options] log_level = info log_file = outputs/run_log.txt [Circuitscape version] version = 4.0.x """ with open("mountain_corridor.conf", "w") as f: f.write(config_text)

这段 Python 脚本把运行参数写进.conf文件。其中connect_scheme = pairwise对应图形界面的连接方案,write_curr_maps开启电流密度图输出,low_memory_mode在内存不足时改为 true。parallelize是我机器 CPU 的核心数,设置成 4 意味着多线程求解,能明显缩短时间,但在内存紧张时建议调回 1。

配置文件名后缀不限,常见用.conf或.ini。之后运行命令行:

ciruitscape mountain_corridor.conf

程序会读取配置文件并执行求解。命令行输出里会滚动显示每一对节点的求解进度,比如Processing pair 1 of 2...。如果程序直接闪退,大概率是栅格路径或节点文件格式出了问题,把日志打开看末尾的报错信息。

4.3 批处理多组阻力面:用 bash 循环替代人工重复

实际项目里很少只跑一组阻力面。比如要对比不同生态阻力赋值方案,或者评估移除某条道路后廊道位置变化,都需要重复运行同一套流程。这时候用 bash 脚本循环最省力。

for res_file in resistance_*.asc; do base_name=$(basename "$res_file" .asc) sed "s|inputs/resistance.asc|inputs/$res_file|g" base_template.conf > "${base_name}.conf" ciruitscape "${base_name}.conf" done

这个循环遍历所有resistance_*.asc文件,每次用 sed 替换基准配置文件里的阻力面路径,生成单独配置并执行。关键点在于模板配置文件里其他路径用相对路径,且输出文件名一定不要写死,否则后一次运行会覆盖前一次结果。更好的做法是在模板里用output_file = outputs/${base_name}_current,配合 sed 一并替换。

批处理能减少重复劳动,但也带来一个问题:一次跑几十组可能中途某一步卡死,整个循环都停掉。我的习惯是每次只生成一组配置跑完验证一遍,确认输出完整后再放开循环。这算是最笨但最稳的跑批方式。

5. 常见问题与避坑排查:我跑 Circuitscape 踩过的五个坑

5.1 电流密度图全为零:节点掉进了 NoData 黑匣子

自己第一次跑项目时,出了一张全黑的电流密度图。当时第一反应是参数传错,折腾很久才发现问题根本不在参数,而是节点文件里有一个质心坐标正好落在 NoData 区域。Circuitscape 遇到这种节点不会报错,直接把它当作无效电极,那一对节点之间自然没有电流。

现象:输出电流密度图全为 0,命令行日志显示 pair 处理完成但没有电流归一化记录。原因:节点落在 NoData 栅格上,或被阻力值为 9999 的高阻值单元包围。解决:把节点文件与阻力面栅格在 GIS 里叠加,逐点检查;如果有节点落在无效区域,把它移动到最近的有效像元中心,再重新导出节点文件。从那以后,我每次新建节点表都要做一次“节点有效性检查”,写成半线性脚本也不复杂。

5.2 结果整幅地图位置偏移:ASCII 文件头被手工改坏了

第二次踩坑是输出结果勉强能看,但跟底图一叠加,电流密度图整体往左上角挪了几百米。查了一下,发现是某次为了裁剪研究区,有人直接用文本编辑器改了 SCI 头里的xllcorner和yllcorner,改完之后没有做栅格对齐验证。

现象:电流密度栅格与阻力面栅格在 GIS 中位置对不上。原因:ASCII 文件头被手工修改过,行列数或角点坐标与原始栅格不一致;或者导出和运行的.asc是两份不同裁剪范围的数据。解决:所有 ASCII 文件在导出后尽量不手工编辑头部,如需裁剪回到 GIS 用标准工具做clip,再重新导出。我的检查流程是每次运行前打印一次文件头与原始 TIFF 对齐信息,确保originX、originY和cellsize完全一致。

5.3 NoData 被误认成高阻力:廊道被无声切断

这不是报错,但结果特别有迷惑性。一次分析中电流密度图显示核心廊道止于某条山脊线,怎么调阻力值都连不通。后来把阻力面单独导出来看,发现那条“山脊线”实际上是边界外的一圈 NoData,而 NoData 在程序里等同于无限电阻,电流根本不可能通过。

现象:两块距离很低的节点之间电流密度极低,廊道像一个被切断的回路。原因:研究区外或数据空值区域的 NoData 没有按“无效区域”处理,程序自动将它变成断路绝缘层,挡住了本该绕行过去的电流。解决:把 NoData 的处理和“真实高阻力”分开。在研究区边界处,可以给外部区域赋一个可见的高阻力值,而不是保留 NoData;或者在形态上先在 GIS 里做掩膜,保证有效区域完全cover目标节点之间的路径范围,再导出 ASCII,不留下会被误判的缺测区。

5.4 内存溢出:大栅格网格粗化反而让结果“糊”

某次对分辨率为 10m 的 4000×4000 栅格直接跑,机器内存占用直接拉满,最后系统报错退出。后来开低内存模式,程序自动把网格粗化到 80m,60 组节点对倒是跑完了,但结果精度明显下降,原来能看出的窄廊道在粗化后完全消失。

现象:程序运行到某一步内存飙升,系统卡死或直接退出。原因:栅格行列数过大,稀疏矩阵求解内存消耗成倍增长;低内存模式自动粗化网格又导致空间分辨率失真。解决:优先用单精度输出减少内存,把low_memory_mode设为 true,但相应地需要手动检查计算网格的行列数变化。如果粗化后的网格超过原始分辨率的 3 倍,就应该考虑裁剪范围或改用更大内存机器,而不是接受糊掉的结果。我自己的经验是在大数据量时,先分区域跑通模型,再拼接电流密度结果,比一次跑全区域更可控。

5.5 命令行找不到可执行文件:路径问题和版本差异

命令行方式最稳,但也会出现“玄学”问题:明明安装好了,在终端里输入ciruitscape却提示 command not found。查后发现是 Windows 下安装目录没有加进 PATH,或者在 Linux 服务器上解压的是源码包而非可执行文件。

现象:终端显示ciruitscape: command not found或类似报错。原因:软件包集解压后没有把可执行文件所在目录加入环境变量;或者是拿到的是源码而非预编译二进制。解决:优先使用绝对路径调用,比如"/opt/circuitscape/current/bin/ciruitscape";也可以把可执行目录导出到 PATH。如果是对源码编译的场景,需要先确认编译依赖已安装,这一步在文档里有详细说明,代码报错一般在编译阶段就会拦截,而不是运行阶段,所以看起来更吓人,实际解决路径却很直白。

6. 进阶技巧:电流密度图不只是看一眼,用阈值提取与敏感性检验收尾

跑完 Circuitscape 拿到电流密度图,很多人直接在 GIS 里用“高电流=廊道”来画线,但这太粗糙,而且一旦系统误差偏高,结论就站不住。我更习惯做两步:阈值提取核心廊道区域,再用节点剔除做敏感性检验。

提取阈值用百分位法。电流密度分布往往偏态,少数瓶颈栅格电流极高,如果按绝对值设定阈值,不同工况间不可比。做法是把所有有效电流栅格按电流密度做直方图,取第 90 分位数作为核心廊道截取阈值。用 GDAL 就能算:

gdal_calc.py -A current.asc --outfile corridor_90pct.tif \ --calc="A >= 320.0" --NoDataValue=0

这里 320.0 是先从直方图读出的 90 分位值。这样得到二值栅格后,再做线状要素化提取中心线。要紧的是把阈值与模拟假设一起写进报告,不然“为什么 90 而不是 60”永远是个黑箱。从那次之后,我每跑一组工况,就固定输出电流直方图阈值表,方便横向比较,也让结论能复现。

敏感性检验是另一道保险。我常用“节点剔除法”:随机去掉一个节点对,重新计算电流密度图,看核心廊道区域是否还保留在原位。如果某个节点的删除导致整条高电流带消失,说明该节点在该网络里是脊柱式的存在,结论应表述为“该廊道依赖于特定节点”,而不是“全域稳定廊道”。在做生态决策时,这种区分非常重要。

我在某山地生态廊道模拟项目里就吃过亏:当时只跑了两组阻力面,画出一条看起来完整的电流高密度带,汇报时被问“如果东北角那片繁殖地断电,这条廊道还成立吗?”我答不上来。后来补了敏感性检验,发现那条廊道确实是被那块地的极高动物群数量假设顶起来的,移除之后电流带位移了十几公里。从那以后,我每次在报告走向建议前,都强制走一遍“先提取阈值、再逐节点剔除验证”的流程,多花半天时间,但结论不再心虚。

如果你正准备复现自己的第一套 Circuitscape 分析,把这份软件包集下载下来,先跑文档自带的示例数据,再替换成自己的阻力面和节点,步骤按第 3 章走通一遍,其余就是反复微调阻力值的事了。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询