1051 lines
40 KiB
Python
1051 lines
40 KiB
Python
# 生成完整的exactextract面积加权计算Python脚本
|
||
# -*- coding: utf-8 -*-
|
||
"""
|
||
土壤属性栅格数据面积加权统计脚本
|
||
基于exactextract库实现多属性栅格的面积加权平均值计算
|
||
最终输出格式与土壤属性图斑数据表一致
|
||
"""
|
||
|
||
import re
|
||
import sys
|
||
|
||
import exactextract as ee
|
||
import geopandas as gpd
|
||
import rasterio
|
||
import pandas as pd
|
||
import numpy as np
|
||
from pathlib import Path
|
||
import warnings
|
||
from pyproj import CRS
|
||
warnings.filterwarnings('ignore')
|
||
|
||
project_root = Path(__file__).parent.parent.parent
|
||
sys.path.insert(0, str(project_root))
|
||
|
||
import app
|
||
|
||
|
||
def init_logger():
|
||
"""初始化日志输出,便于跟踪处理过程"""
|
||
import logging
|
||
logging.basicConfig(
|
||
level=logging.INFO,
|
||
format='%(asctime)s - %(levelname)s - %(message)s',
|
||
datefmt='%Y-%m-%d %H:%M:%S'
|
||
)
|
||
return logging.getLogger(__name__)
|
||
|
||
def validate_data(vector_path, raster_files):
|
||
"""
|
||
验证输入数据的有效性
|
||
:param vector_path: 矢量图斑文件路径
|
||
:param raster_files: 栅格文件字典
|
||
:return: 验证结果(布尔值)
|
||
"""
|
||
logger = init_logger()
|
||
|
||
# 验证矢量文件是否存在
|
||
# if not Path(vector_path).exists():
|
||
# logger.error(f"矢量文件不存在:{vector_path}")
|
||
# return False
|
||
|
||
# 验证栅格文件是否存在
|
||
for attr_name, raster_path in raster_files.items():
|
||
if not Path(raster_path).exists():
|
||
logger.error(f"栅格文件不存在:{attr_name} -> {raster_path}")
|
||
return False
|
||
|
||
# 验证矢量文件格式
|
||
try:
|
||
# gdf = gpd.read_file(vector_path)
|
||
gdf = app.readers.read_vector(vector_path)
|
||
if gdf.geometry.type.unique()[0] != 'Polygon' and gdf.geometry.type.unique()[0] != 'MultiPolygon':
|
||
logger.error("矢量文件必须是Polygon类型(面要素)")
|
||
return False
|
||
except Exception as e:
|
||
logger.error(f"矢量文件读取失败:{str(e)}")
|
||
return False
|
||
|
||
# 验证栅格文件格式
|
||
try:
|
||
test_raster = next(iter(raster_files.values()))
|
||
with rasterio.open(test_raster) as src:
|
||
if src.count != 1:
|
||
logger.error("每个栅格文件必须是单波段(每个属性单独一个栅格)")
|
||
return False
|
||
except Exception as e:
|
||
logger.error(f"栅格文件读取失败:{str(e)}")
|
||
return False
|
||
|
||
logger.info("所有输入数据验证通过")
|
||
return True
|
||
|
||
def extract_epsg(crs_obj):
|
||
"""
|
||
终极EPSG提取器:从正常方法到暴力正则
|
||
"""
|
||
if crs_obj is None:
|
||
return None
|
||
|
||
# 1. 尝试常规方法
|
||
epsg = crs_obj.to_epsg()
|
||
if epsg:
|
||
return str(epsg)
|
||
|
||
# 2. 降低匹配严格度尝试 (pyproj 内置的容错方法)
|
||
epsg_loose = crs_obj.to_epsg(min_confidence=25)
|
||
if epsg_loose:
|
||
return str(epsg_loose)
|
||
|
||
# 3. 终极必杀:正则匹配 WKT 文本
|
||
try:
|
||
wkt_str = crs_obj.to_wkt()
|
||
# 匹配文本中的 AUTHORITY["EPSG","4523"] 或 ID["EPSG", 4523]
|
||
matches = re.findall(r'(?:AUTHORITY|ID)\["EPSG",\s*"?(\d+)"?\]', wkt_str)
|
||
if matches:
|
||
# WKT中会有多个EPSG(比如单位、椭球体),最后一个通常才是整个坐标系的EPSG
|
||
return matches[-1]
|
||
except Exception as e:
|
||
pass
|
||
|
||
return None
|
||
|
||
def standardize_crs(gdf, raster_path):
|
||
"""
|
||
标准化矢量与栅格的坐标参考系统(CRS)
|
||
"""
|
||
logger = init_logger() # 请确保你有 init_logger
|
||
|
||
with rasterio.open(raster_path) as src:
|
||
# 兼容旧版本 rasterio 的读取方式
|
||
raster_crs = CRS.from_user_input(src.crs)
|
||
|
||
vector_crs = CRS.from_user_input(gdf.crs)
|
||
|
||
# 使用终极提取器获取 EPSG
|
||
v_epsg = extract_epsg(vector_crs)
|
||
r_epsg = extract_epsg(raster_crs)
|
||
|
||
print(f"当前矢量CRS EPSG:{v_epsg}")
|
||
print(f"目标栅格CRS EPSG:{r_epsg}")
|
||
|
||
# 判断逻辑:先看数学是否相等,再看强制提取的EPSG编号是否相等
|
||
is_same_crs = False
|
||
if vector_crs.equals(raster_crs):
|
||
is_same_crs = True
|
||
elif v_epsg and r_epsg and v_epsg == r_epsg:
|
||
is_same_crs = True
|
||
|
||
# 执行转换(若真的不同才转)
|
||
if not is_same_crs:
|
||
logger.warning("矢量与栅格CRS不一致,正在进行转换...")
|
||
gdf = gdf.to_crs(raster_crs)
|
||
new_epsg = extract_epsg(CRS.from_user_input(gdf.crs))
|
||
logger.info(f"CRS转换完成,新矢量CRS EPSG:{new_epsg}")
|
||
else:
|
||
logger.info(f"矢量与栅格CRS一致 (均判定为 EPSG:{v_epsg}),无需转换。")
|
||
|
||
return gdf
|
||
|
||
def calculate_area_weighted_stats(vector_path, raster_files, output_path):
|
||
"""
|
||
核心函数:计算面积加权统计值
|
||
:param vector_path: 矢量图斑文件路径
|
||
:param raster_files: 栅格文件字典(键:属性名,值:栅格路径)
|
||
:param output_path: 结果输出路径(Excel文件)
|
||
:return: 统计结果DataFrame
|
||
"""
|
||
logger = init_logger()
|
||
logger.info("开始面积加权统计计算")
|
||
|
||
# 1. 加载矢量数据
|
||
logger.info(f"加载矢量数据:{vector_path}")
|
||
gdf = app.readers.read_vector(vector_path)
|
||
|
||
# 2. 标准化CRS
|
||
test_raster = next(iter(raster_files.values()))
|
||
gdf = standardize_crs(gdf, test_raster)
|
||
|
||
# 中断程序
|
||
# sys.exit(0)
|
||
|
||
# 3. 初始化结果DataFrame(保留矢量中的关键属性)
|
||
logger.info("初始化结果数据结构")
|
||
# 基础字段列表(与土壤属性图斑表格式对齐)
|
||
# TODO
|
||
base_fields = ["BSM","YSDM","TBBH","DLBM", "DLMC","TL", "YL", "TS", "TZ","ZLDWDM","ZLDWMC","TBMJ","geometry"]
|
||
|
||
# 检查矢量中是否包含必要字段,若不包含则创建空字段
|
||
result_gdf = gpd.GeoDataFrame()
|
||
for field in base_fields:
|
||
if field in gdf.columns:
|
||
result_gdf[field] = gdf[field]
|
||
else:
|
||
result_gdf[field] = np.nan
|
||
logger.warning(f"矢量中缺少'{field}'字段,将生成空值")
|
||
|
||
# 设置几何列以保持GeoDataFrame
|
||
result_gdf = gpd.GeoDataFrame(result_gdf, geometry=gdf.geometry)
|
||
|
||
# 4. 计算图斑面积(转换为亩)
|
||
# logger.info("计算图斑面积(单位:亩)")
|
||
# # 计算平方米面积(根据CRS单位自动适应)
|
||
# gdf["area_sqm"] = gdf.geometry.area
|
||
# # 转换为亩(1亩 ≈ 666.6667平方米)
|
||
# result_gdf["面积亩"] = gdf["area_sqm"] * 0.0015
|
||
# # 保留6位小数,与示例数据格式一致
|
||
# result_gdf["面积亩"] = result_gdf["面积亩"].round(6)
|
||
|
||
# 5. 对每个土壤属性进行面积加权平均计算
|
||
logger.info("开始处理土壤属性栅格(面积加权平均)")
|
||
for attr_idx, (attr_name, raster_path) in enumerate(raster_files.items(), 1):
|
||
total_attrs = len(raster_files)
|
||
logger.info(f"处理进度:{attr_idx}/{total_attrs} - 属性:{attr_name}")
|
||
|
||
try:
|
||
# 使用exactextract计算面积加权平均
|
||
# weights="area":按矢量与栅格的交集面积进行加权,如果是TRZD等分类属性,则不使用面积加权,直接计算众数
|
||
if attr_name in ["TRZD"]:
|
||
stats = ee.exact_extract(
|
||
raster_path,
|
||
gdf,
|
||
["majority"], # 计算众数
|
||
output="pandas" # 输出为DataFrame格式
|
||
)
|
||
else:
|
||
stats = ee.exact_extract(
|
||
raster_path,
|
||
gdf,
|
||
["mean"], # 计算平均值
|
||
output="pandas" # 输出为DataFrame格式
|
||
)
|
||
|
||
# 将统计结果添加到结果DataFrame
|
||
if stats is None:
|
||
logger.warning(f"{attr_name}计算结果为空,可能无交集区域")
|
||
result_gdf[attr_name] = np.nan
|
||
continue
|
||
else:
|
||
# 确保 stats 为 pandas.DataFrame,以便使用字符串索引
|
||
if not isinstance(stats, pd.DataFrame):
|
||
stats = pd.DataFrame(stats)
|
||
|
||
# 保留4位小数,确保数据精度
|
||
if attr_name in ["TRZD"]:
|
||
result_gdf[attr_name] = stats["majority"]
|
||
else:
|
||
result_gdf[attr_name] = stats["mean"].round(2)
|
||
|
||
# 处理可能的空值(无交集区域)
|
||
if result_gdf[attr_name].isnull().sum() > 0:
|
||
null_count = result_gdf[attr_name].isnull().sum()
|
||
logger.warning(f"{attr_name}存在{null_count}个空值(图斑与栅格无交集)")
|
||
# 用0填充空值(可根据业务需求调整)
|
||
result_gdf[attr_name] = result_gdf[attr_name].fillna(0)
|
||
|
||
except Exception as e:
|
||
logger.error(f"{attr_name}处理失败:{str(e)}")
|
||
# 失败时填充空值,避免整个程序崩溃
|
||
result_gdf[attr_name] = np.nan
|
||
|
||
# 6. 添加属性分级字段(根据业务规则实现)
|
||
logger.info("添加土壤属性分级字段")
|
||
result_gdf = add_attribute_classification(result_gdf)
|
||
|
||
# 7. 整理最终字段顺序(与示例表格完全对齐)
|
||
logger.info("整理输出字段顺序")
|
||
# TODO
|
||
final_columns = [
|
||
"BSM","YSDM","TBBH","DLBM", "DLMC","TL", "YL", "TS", "TZ","ZLDWDM","ZLDWMC","TBMJ",
|
||
"SL", "FL", "NL", "TRZD", "GZCHD", "TRRZ", "SWXDT", "DBLSFD",
|
||
"PH", "CEC", "OM", "TN", "TP", "TK", "AP", "AK", "ECA", "EMG",
|
||
"AS1", "AFE", "AMN", "ACU","AZN","AB","AMO",
|
||
"SL_DJ", "FL_DJ", "NL_DJ", "TRZD_DJ", "GZCHD_DJ", "TRRZ_DJ", "SWXDT_DJ", "DBLSFD_DJ",
|
||
"PH_DJ", "CEC_DJ", "OM_DJ", "TN_DJ", "TP_DJ", "TK_DJ", "AP_DJ", "AK_DJ", "ECA_DJ", "EMG_DJ",
|
||
"AS1_DJ", "AFE_DJ", "AMN_DJ", "ACU_DJ","AZN_DJ","AB_DJ","AMO_DJ",
|
||
"SL_DJZY", "FL_DJZY", "NL_DJZY", "TRZD_DJZY", "GZCHD_DJZY", "TRRZ_DJZY", "SWXDT_DJZY", "DBLSFD_DJZY",
|
||
"PH_DJZY", "CEC_DJZY", "OM_DJZY", "TN_DJZY", "TP_DJZY", "TK_DJZY", "AP_DJZY", "AK_DJZY", "ECA_DJZY", "EMG_DJZY",
|
||
"AS1_DJZY", "AFE_DJZY", "AMN_DJZY", "ACU_DJZY","AZN_DJZY","AB_DJZY","AMO_DJZY",
|
||
"geometry" # 保留几何列以保持GeoDataFrame
|
||
]
|
||
|
||
# 补充缺失的字段(如乡代码等)
|
||
for col in final_columns:
|
||
if col not in result_gdf.columns:
|
||
result_gdf[col] = np.nan
|
||
|
||
# 按最终顺序排列字段
|
||
result_gdf = result_gdf[final_columns]
|
||
|
||
# 8. 导出结果到Excel
|
||
logger.info(f"导出结果到:{output_path}")
|
||
# 使用openpyxl引擎支持.xlsx格式
|
||
# result_gdf.to_excel(output_path, index=False, engine="openpyxl")
|
||
result_gdf.to_file(output_path, index=False, driver="ESRI Shapefile") # 导出为GeoPackage格式,保留空间信息
|
||
logger.info(f"结果导出完成,共生成{len(result_gdf)}条记录")
|
||
|
||
return result_gdf
|
||
|
||
def add_attribute_classification(df):
|
||
"""
|
||
添加土壤属性分级字段(根据常见土壤分类标准实现)
|
||
可根据实际业务需求调整分级阈值
|
||
:param df: 包含原始属性的DataFrame
|
||
:return: 包含分级字段和分级值域的DataFrame
|
||
"""
|
||
# todo
|
||
# 1. 酸碱度分级(pH值) - 按PH标准
|
||
def classify_ph(ph):
|
||
"""
|
||
土壤pH值分级(第三次全国土壤普查标准)
|
||
标准等级:
|
||
等级一: 6.0~7.0
|
||
等级二: 7.0~7.5, 5.5~6.0
|
||
等级三: 7.5~8.0, 5.0~5.5
|
||
等级四: 8.0~8.5, 4.5~5.0
|
||
等级五: >8.5, ≤4.5
|
||
"""
|
||
if ph > 8.5 or ph <= 4.5:
|
||
return 5 # 等级五: >8.5, ≤4.5
|
||
elif (8.0 < ph <= 8.5) or (4.5 < ph <= 5.0):
|
||
return 4 # 等级四: 8.0~8.5, 4.5~5.0
|
||
elif (7.5 < ph <= 8.0) or (5.0 < ph <= 5.5):
|
||
return 3 # 等级三: 7.5~8.0, 5.0~5.5
|
||
elif (7.0 < ph <= 7.5) or (5.5 < ph <= 6.0):
|
||
return 2 # 等级二: 7.0~7.5, 5.5~6.0
|
||
elif 6.0 < ph <= 7.0:
|
||
return 1 # 等级一: 6.0~7.0
|
||
else:
|
||
return None # 异常值
|
||
|
||
# 2. 有机质分级(单位:g/kg) - 按OM标准
|
||
def classify_organic(organic):
|
||
"""
|
||
土壤有机质分级(第三次全国土壤普查标准)
|
||
标准等级:
|
||
等级一: >35.0
|
||
等级二: 25.0~35.0
|
||
等级三: 15.0~25.0
|
||
等级四: 10.0~15.0
|
||
等级五: ≤10.0
|
||
"""
|
||
if organic > 35.0:
|
||
return 1 # 等级一: >35.0
|
||
elif 30.0 < organic <= 35.0:
|
||
return 2 # 等级二: 25.0~35.0
|
||
elif 20.0 < organic <= 30.0:
|
||
return 3 # 等级三: 15.0~25.0
|
||
elif 10.0 < organic <= 20.0:
|
||
return 4 # 等级四: 10.0~15.0
|
||
elif organic <= 10.0:
|
||
return 5 # 等级五: ≤10.0
|
||
else:
|
||
return None # 异常值
|
||
|
||
# 3. 阳离子交换量分级(单位:cmol/kg) - 按CEC标准
|
||
def classify_cation(cation):
|
||
"""
|
||
土壤阳离子交换量分级(第三次全国土壤普查标准)
|
||
标准等级:
|
||
等级一: >20.0
|
||
等级二: 15.0~20.0
|
||
等级三: 10.0~15.0
|
||
等级四: 5.0~10.0
|
||
等级五: ≤5.0
|
||
"""
|
||
if cation > 20.0:
|
||
return 1 # 等级一: >20.0
|
||
elif 15.0 < cation <= 20.0:
|
||
return 2 # 等级二: 15.0~20.0
|
||
elif 10.0 < cation <= 15.0:
|
||
return 3 # 等级三: 10.0~15.0
|
||
elif 5.0 < cation <= 10.0:
|
||
return 4 # 等级四: 5.0~10.0
|
||
elif cation <= 5.0:
|
||
return 5 # 等级五: ≤5.0
|
||
else:
|
||
return None # 异常值
|
||
|
||
# 4. 有效磷分级(单位:mg/kg) - 按AP标准
|
||
def classify_available_p(p):
|
||
"""
|
||
土壤有效磷分级(第三次全国土壤普查标准)
|
||
标准等级:
|
||
等级一: >40.0
|
||
等级二: 20.0~40.0
|
||
等级三: 10.0~20.0
|
||
等级四: 5.0~10.0
|
||
等级五: ≤5.0
|
||
"""
|
||
if p > 40.0:
|
||
return 1 # 等级一: >40.0
|
||
elif 20.0 < p <= 40.0:
|
||
return 2 # 等级二: 25.0~40.0
|
||
elif 10.0 < p <= 20.0:
|
||
return 3 # 等级三: 15.0~25.0
|
||
elif 5.0 < p <= 10.0:
|
||
return 4 # 等级四: 5.0~15.0
|
||
elif p <= 5.0:
|
||
return 5 # 等级五: ≤5.0
|
||
else:
|
||
return None # 异常值
|
||
|
||
# 5. 速效钾分级(单位:mg/kg) - 按AK标准
|
||
def classify_available_k(k):
|
||
"""
|
||
土壤速效钾分级(第三次全国土壤普查标准)
|
||
标准等级:
|
||
等级一: >150
|
||
等级二: 100~150
|
||
等级三: 75~100
|
||
等级四: 50~75
|
||
等级五: ≤50
|
||
"""
|
||
if k > 150:
|
||
return 1 # 等级一: >150
|
||
elif 100 < k <= 150:
|
||
return 2 # 等级二: 100~150
|
||
elif 75 < k <= 100:
|
||
return 3 # 等级三: 75~100
|
||
elif 50 < k <= 75:
|
||
return 4 # 等级四: 50~75
|
||
elif k <= 50:
|
||
return 5 # 等级五: ≤50
|
||
else:
|
||
return None # 异常值
|
||
|
||
# 6. 耕层厚度分级(单位:cm) - 按GZCHD标准
|
||
def classify_soil_depth(depth):
|
||
"""
|
||
土壤耕作层厚度分级(第三次全国土壤普查标准)
|
||
标准等级:
|
||
等级一: >25.0
|
||
等级二: 20.0~25.0
|
||
等级三: 15.0~20.0
|
||
等级四: 10.0~15.0
|
||
等级五: ≤10.0
|
||
"""
|
||
if depth > 25.0:
|
||
return 1 # 等级一: >25.0
|
||
elif 20.0 < depth <= 25.0:
|
||
return 2 # 等级二: 20.0~25.0
|
||
elif 15.0 < depth <= 20.0:
|
||
return 3 # 等级三: 15.0~20.0
|
||
elif 10.0 < depth <= 15.0:
|
||
return 4 # 等级四: 10.0~15.0
|
||
elif depth <= 10.0:
|
||
return 5 # 等级五: ≤10.0
|
||
else:
|
||
return None # 异常值
|
||
|
||
# 7. 土壤容重分级(单位:g/cm³) - 按TRRZ标准
|
||
def classify_bulk_density(density):
|
||
"""
|
||
土壤容重分级(第三次全国土壤普查标准)
|
||
标准等级:
|
||
等级一: 1.00~1.20
|
||
等级二: 1.20~1.30
|
||
等级三: 1.30~1.40, 0.90~1.00
|
||
等级四: 1.40~1.50
|
||
等级五: >1.50, ≤0.90
|
||
"""
|
||
if 1.00 < density <= 1.20:
|
||
return 1 # 等级一: 1.00~1.20
|
||
elif 1.20 < density <= 1.30:
|
||
return 2 # 等级二: 1.20~1.30
|
||
elif (1.30 < density <= 1.40) or (0.90 < density <= 1.00):
|
||
return 3 # 等级三: 1.30~1.40, 0.90~1.00
|
||
elif 1.40 < density <= 1.50:
|
||
return 4 # 等级四: 1.40~1.50
|
||
elif density > 1.50 or density <= 0.90:
|
||
return 5 # 等级五: >1.50, ≤0.90
|
||
else:
|
||
return None # 异常值
|
||
|
||
# 8. 全氮分级(单位:g/kg) - 按TN标准
|
||
def classify_total_n(n):
|
||
"""
|
||
土壤全氮分级(第三次全国土壤普查标准)
|
||
标准等级:
|
||
等级一: >2.00
|
||
等级二: 1.50~2.00
|
||
等级三: 1.00~1.50
|
||
等级四: 0.50~1.00
|
||
等级五: ≤0.50
|
||
"""
|
||
if n > 2.00:
|
||
return 1 # 等级一: >2.00
|
||
elif 1.50 < n <= 2.00:
|
||
return 2 # 等级二: 1.50~2.00
|
||
elif 1.00 < n <= 1.50:
|
||
return 3 # 等级三: 1.00~1.50
|
||
elif 0.50 < n <= 1.00:
|
||
return 4 # 等级四: 0.50~1.00
|
||
elif n <= 0.50:
|
||
return 5 # 等级五: ≤0.50
|
||
else:
|
||
return None # 异常值
|
||
|
||
# 9. 全磷分级(单位:g/kg) - 按TP标准
|
||
def classify_total_p(p):
|
||
"""
|
||
土壤全磷分级(第三次全国土壤普查标准)
|
||
标准等级:
|
||
等级一: >1.50
|
||
等级二: 1.00~1.50
|
||
等级三: 0.60~1.00
|
||
等级四: 0.40~0.60
|
||
等级五: ≤0.40
|
||
"""
|
||
if p > 1.50:
|
||
return 1 # 等级一: >1.50
|
||
elif 1.00 < p <= 1.50:
|
||
return 2 # 等级二: 1.00~1.50
|
||
elif 0.60 < p <= 1.00:
|
||
return 3 # 等级三: 0.60~1.00
|
||
elif 0.40 <= p <= 0.60:
|
||
return 4 # 等级四: 0.40~0.60
|
||
elif p <= 0.40:
|
||
return 5 # 等级五: ≤0.40
|
||
else:
|
||
return None # 异常值
|
||
|
||
# 10. 全钾分级(单位:g/kg) - 按TK标准
|
||
def classify_total_k(k):
|
||
"""
|
||
土壤全钾分级(第三次全国土壤普查标准)
|
||
标准等级:
|
||
等级一: >20.0
|
||
等级二: 15.0~20.0
|
||
等级三: 10.0~15.0
|
||
等级四: 5.0~10.0
|
||
等级五: ≤5.0
|
||
"""
|
||
if k > 20.0:
|
||
return 1 # 等级一: >20.0
|
||
elif 15.0 < k <= 20.0:
|
||
return 2 # 等级二: 15.0~20.0
|
||
elif 10.0 < k <= 15.0:
|
||
return 3 # 等级三: 10.0~15.0
|
||
elif 5.0 < k <= 10.0:
|
||
return 4 # 等级四: 5.0~10.0
|
||
elif k <= 5.0:
|
||
return 5 # 等级五: ≤5.0
|
||
else:
|
||
return None # 异常值
|
||
|
||
# 11. 有效铁分级(单位:mg/kg)
|
||
def classify_available_fe(fe):
|
||
"""
|
||
土壤有效铁分级(第三次全国土壤普查标准)
|
||
|
||
参数:
|
||
fe: 有效铁含量 (mg/kg)
|
||
|
||
返回:
|
||
分级等级 (1-5)
|
||
"""
|
||
if fe <= 3.0:
|
||
return 5 # 等级五: ≤3.0
|
||
elif 3.0 < fe <= 8.0:
|
||
return 4 # 等级四: 3.0~8.0
|
||
elif 8.0 < fe <= 10.0:
|
||
return 3 # 等级三: 8.0~10.0
|
||
elif 10.0 < fe <= 20.0:
|
||
return 2 # 等级二: 10.0~20.0
|
||
else: # fe > 20.0
|
||
return 1 # 等级一: >20.0
|
||
|
||
# 12. 有效锌分级(单位:mg/kg)
|
||
def classify_available_zn(zn):
|
||
"""
|
||
土壤有效锌分级(第三次全国土壤普查标准)
|
||
|
||
参数:
|
||
zn: 有效锌含量 (mg/kg)
|
||
|
||
返回:
|
||
分级等级 (1-5)
|
||
"""
|
||
if zn <= 0.50:
|
||
return 5 # 等级五: ≤0.50
|
||
elif 0.50 < zn <= 1.00:
|
||
return 4 # 等级四: 0.50~1.00
|
||
elif 1.00 < zn <= 2.00:
|
||
return 3 # 等级三: 1.00~2.00
|
||
elif 2.00 < zn <= 3.00:
|
||
return 2 # 等级二: 2.00~3.00
|
||
else: # zn > 3.00
|
||
return 1 # 等级一: >3.00
|
||
|
||
# 13. 有效锰分级(单位:mg/kg)
|
||
def classify_available_mn(mn):
|
||
"""
|
||
土壤有效锰分级(第三次全国土壤普查标准)
|
||
|
||
参数:
|
||
mn: 有效锰含量 (mg/kg)
|
||
|
||
返回:
|
||
分级等级 (1-5)
|
||
"""
|
||
if mn <= 5.0:
|
||
return 5 # 等级五: ≤5.0
|
||
elif 5.0 < mn <= 10.0:
|
||
return 4 # 等级四: 5.0~10.0
|
||
elif 10.0 < mn <= 20.0:
|
||
return 3 # 等级三: 10.0~20.0
|
||
elif 20.0 < mn <= 30.0:
|
||
return 2 # 等级二: 20.0~30.0
|
||
else: # mn > 30.0
|
||
return 1 # 等级一: >30.0
|
||
|
||
# 14. 有效铜分级(单位:mg/kg)
|
||
def classify_available_cu(cu):
|
||
"""
|
||
土壤有效铜分级(第三次全国土壤普查标准)
|
||
|
||
参数:
|
||
cu: 有效铜含量 (mg/kg)
|
||
|
||
返回:
|
||
分级等级 (1-5)
|
||
"""
|
||
if cu <= 0.20:
|
||
return 5 # 等级五: ≤0.20
|
||
elif 0.20 < cu <= 0.50:
|
||
return 4 # 等级四: 0.20~0.50
|
||
elif 0.50 < cu <= 1.00:
|
||
return 3 # 等级三: 0.50~1.00
|
||
elif 1.00 < cu <= 1.80:
|
||
return 2 # 等级二: 1.00~1.80
|
||
else: # cu > 1.80
|
||
return 1 # 等级一: >1.80
|
||
|
||
# 15. 有效硼分级(单位:mg/kg)
|
||
def classify_available_b(b):
|
||
"""
|
||
土壤有效硼分级(第三次全国土壤普查标准)
|
||
|
||
参数:
|
||
b: 有效硼含量 (mg/kg)
|
||
|
||
返回:
|
||
分级等级 (1-5)
|
||
"""
|
||
if b <= 0.20:
|
||
return 5 # 等级五: ≤0.20
|
||
elif 0.20 < b <= 0.50:
|
||
return 4 # 等级四: 0.20~0.50
|
||
elif 0.50 < b <= 1.00:
|
||
return 3 # 等级三: 0.50~1.00
|
||
elif 1.00 < b <= 2.00:
|
||
return 2 # 等级二: 1.00~2.00
|
||
else: # b > 2.00
|
||
return 1 # 等级一: >2.00
|
||
|
||
# 16. 有效钼分级(单位:mg/kg)
|
||
def classify_available_mo(mo):
|
||
"""
|
||
土壤有效钼分级(第三次全国土壤普查标准)
|
||
|
||
参数:
|
||
mo: 有效钼含量 (mg/kg)
|
||
|
||
返回:
|
||
分级等级 (1-5)
|
||
"""
|
||
if mo <= 0.05:
|
||
return 5 # 等级五: ≤0.05
|
||
elif 0.05 < mo <= 0.10:
|
||
return 4 # 等级四: 0.05~0.10
|
||
elif 0.10 < mo <= 0.15:
|
||
return 3 # 等级三: 0.10~0.15
|
||
elif 0.15 < mo <= 0.20:
|
||
return 2 # 等级二: 0.15~0.20
|
||
else: # mo > 0.20
|
||
return 1 # 等级一: >0.20
|
||
|
||
# 17. 有效硫分级(单位:mg/kg)
|
||
def classify_available_s(s):
|
||
"""
|
||
土壤有效硫分级(第三次全国土壤普查标准)
|
||
|
||
参数:
|
||
s: 有效硫含量 (mg/kg)
|
||
|
||
返回:
|
||
分级等级 (1-5)
|
||
"""
|
||
if s <= 10.0:
|
||
return 5 # 等级五: ≤10.0
|
||
elif 10.0 < s <= 20.0:
|
||
return 4 # 等级四: 10.0~20.0
|
||
elif 20.0 < s <= 30.0:
|
||
return 3 # 等级三: 20.0~30.0
|
||
elif 30.0 < s <= 40.0:
|
||
return 2 # 等级二: 30.0~40.0
|
||
else: # s > 40.0
|
||
return 1 # 等级一: >40.0
|
||
|
||
# 18. 交换性钙分级(单位:cmol(½Ca²⁺)/kg)
|
||
def classify_exchangeable_ca(ca):
|
||
"""
|
||
土壤交换性钙分级(第三次全国土壤普查标准)
|
||
|
||
参数:
|
||
ca: 交换性钙含量 (cmol(½Ca²⁺)/kg)
|
||
|
||
返回:
|
||
分级等级 (1-5)
|
||
"""
|
||
if ca <= 0.25:
|
||
return 5 # 等级五: ≤0.25
|
||
elif 0.25 < ca <= 1.00:
|
||
return 4 # 等级四: 0.25~1.00
|
||
elif 1.00 < ca <= 2.50:
|
||
return 3 # 等级三: 1.00~2.50
|
||
elif 2.50 < ca <= 4.99:
|
||
return 2 # 等级二: 2.50~4.99
|
||
else: # ca > 4.99
|
||
return 1 # 等级一: >4.99
|
||
|
||
# 19. 交换性镁分级(单位:cmol(½Mg²⁺)/kg)
|
||
def classify_exchangeable_mg(mg):
|
||
"""
|
||
土壤交换性镁分级(第三次全国土壤普查标准)
|
||
|
||
参数:
|
||
mg: 交换性镁含量 (cmol(½Mg²⁺)/kg)
|
||
|
||
返回:
|
||
分级等级 (1-5)
|
||
"""
|
||
if mg <= 0.21:
|
||
return 5 # 等级五: ≤0.21
|
||
elif 0.21 < mg <= 0.41:
|
||
return 4 # 等级四: 0.21~0.41
|
||
elif 0.41 < mg <= 0.82:
|
||
return 3 # 等级三: 0.41~0.82
|
||
elif 0.82 < mg <= 1.64:
|
||
return 2 # 等级二: 0.82~1.64
|
||
else: # mg > 1.64
|
||
return 1 # 等级一: >1.64
|
||
|
||
# 20. 全硒分级(单位:mg/kg)
|
||
def classify_total_se(se):
|
||
"""
|
||
土壤全硒分级(第三次全国土壤普查标准)
|
||
|
||
参数:
|
||
se: 全硒含量 (mg/kg)
|
||
|
||
返回:
|
||
分级等级 (1-4)
|
||
"""
|
||
if se <= 0.17:
|
||
return 4 # 等级四: ≤0.17
|
||
elif 0.17 < se <= 0.40:
|
||
return 3 # 等级三: 0.17~0.40
|
||
elif 0.40 < se <= 3.00:
|
||
return 2 # 等级二: 0.40~3.00
|
||
else: # se > 3.00
|
||
return 1 # 等级一: >3.00
|
||
|
||
# 21. 粉粒含量分级(单位:%)
|
||
def classify_silt(silt):
|
||
"""
|
||
土壤粉粒含量分级(第三次全国土壤普查标准)
|
||
|
||
参数:
|
||
silt: 粉粒含量 (%)
|
||
|
||
返回:
|
||
分级等级 (1-5)
|
||
"""
|
||
if silt > 75:
|
||
return 5 # 等级五: >75
|
||
elif 45 < silt <= 75:
|
||
return 4 # 等级四: 45~75
|
||
elif 30 < silt <= 45:
|
||
return 3 # 等级三: 30~45
|
||
elif 15 < silt <= 30:
|
||
return 2 # 等级二: 15~30
|
||
else: # silt <= 15
|
||
return 1 # 等级一: ≤15
|
||
|
||
# 22. 黏粒含量分级(单位:%)
|
||
def classify_clay(clay):
|
||
"""
|
||
土壤黏粒含量分级(第三次全国土壤普查标准)
|
||
|
||
参数:
|
||
clay: 黏粒含量 (%)
|
||
|
||
返回:
|
||
分级等级 (1-5)
|
||
"""
|
||
if clay > 65:
|
||
return 5 # 等级五: >65
|
||
elif 45 < clay <= 65:
|
||
return 4 # 等级四: 45~65
|
||
elif 25 < clay <= 45:
|
||
return 3 # 等级三: 25~45
|
||
elif 15 < clay <= 25:
|
||
return 2 # 等级二: 15~25
|
||
else: # clay <= 15
|
||
return 1 # 等级一: ≤15
|
||
|
||
# 23. 砂粒含量分级(单位:%)
|
||
def classify_sand(sand):
|
||
"""
|
||
土壤砂粒含量分级(第三次全国土壤普查标准)
|
||
|
||
参数:
|
||
sand: 砂粒含量 (%)
|
||
|
||
返回:
|
||
分级等级 (1-5)
|
||
"""
|
||
if sand > 85:
|
||
return 5 # 等级五: >85
|
||
elif 55 < sand <= 85:
|
||
return 4 # 等级四: 55~85
|
||
elif 40 < sand <= 55:
|
||
return 3 # 等级三: 40~55
|
||
elif 30 < sand <= 40:
|
||
return 2 # 等级二: 30~40
|
||
else: # sand <= 30
|
||
return 1 # 等级一: ≤30
|
||
|
||
# 24. 有效土层厚度分级(单位:cm)
|
||
def classify_yxtchd(depth):
|
||
"""
|
||
土壤有效土层厚度分级(第三次全国土壤普查标准)
|
||
|
||
参数:
|
||
depth: 有效土层厚度 (cm)
|
||
|
||
返回:
|
||
分级等级 (1-5)
|
||
"""
|
||
if depth <= 40:
|
||
return 5 # 等级五: ≤40
|
||
elif 40 < depth <= 60:
|
||
return 4 # 等级四: 40~60
|
||
elif 60 < depth <= 80:
|
||
return 3 # 等级三: 60~80
|
||
elif 80 < depth <= 100:
|
||
return 2 # 等级二: 80~100
|
||
else: # depth > 100
|
||
return 1 # 等级一: >100
|
||
|
||
# 25. 土壤质地
|
||
def classify_trzd(trzd):
|
||
"""
|
||
土壤质地
|
||
|
||
参数:
|
||
trzd: 土壤质地分类(1-5)
|
||
|
||
返回:
|
||
分级等级 (1-5)
|
||
"""
|
||
trzd = round(trzd, 0)
|
||
return trzd
|
||
# if trzd == 5:
|
||
# return 5 # 等级五: ≤40
|
||
# elif trzd == 4:
|
||
# return 4 # 等级四: 40~60
|
||
# elif trzd == 3:
|
||
# return 3 # 等级三: 60~80
|
||
# elif trzd == 2:
|
||
# return 2 # 等级二: 80~100
|
||
# else: # depth > 100
|
||
# return 1 # 等级一: >100
|
||
|
||
# 26. 地表砾石丰度分级(单位:%)
|
||
def classify_lsfd(gravel):
|
||
"""
|
||
土壤地表砾石丰度分级(第三次全国土壤普查标准)
|
||
|
||
参数:
|
||
gravel: 地表砾石丰度 (%)
|
||
|
||
返回:
|
||
分级等级 (1-5)
|
||
"""
|
||
if gravel <= 0:
|
||
return 1 # 等级一: ≤0
|
||
elif 0 < gravel <= 5:
|
||
return 2 # 等级二: 0~5
|
||
elif 5 < gravel <= 15:
|
||
return 3 # 等级三: 5~15
|
||
elif 15 < gravel <= 50:
|
||
return 4 # 等级三: 15~50
|
||
else: # gravel > 50
|
||
return 5 # 等级五: >50
|
||
|
||
# 应用分级函数(只处理非空值)
|
||
if "PH" in df.columns:
|
||
df["PH_DJ"] = df["PH"].apply(lambda x: classify_ph(x) if pd.notna(x) else np.nan)
|
||
df["PH_DJZY"] = "等级一: 6.0~7.0,等级二: 7.0~7.5, 5.5~6.0,等级三: 7.5~8.0, 5.0~5.5,等级四: 8.0~8.5, 4.5~5.0,等级五: >8.5, ≤4.5"
|
||
if "OM" in df.columns:
|
||
df["OM_DJ"] = df["OM"].apply(lambda x: classify_organic(x) if pd.notna(x) else np.nan)
|
||
df["OM_DJZY"] = "等级一: >35,等级二: 30~35,等级三: 20~30,等级四: 10~20,等级五: ≤10"
|
||
if "CEC" in df.columns:
|
||
df["CEC_DJ"] = df["CEC"].apply(lambda x: classify_cation(x) if pd.notna(x) else np.nan)
|
||
df["CEC_DJZY"] = "等级一: >20,等级二: 15~20,等级三: 10~15,等级四: 5~10,等级五: ≤5"
|
||
if "AP" in df.columns:
|
||
df["AP_DJ"] = df["AP"].apply(lambda x: classify_available_p(x) if pd.notna(x) else np.nan)
|
||
df["AP_DJZY"] = "等级一: >40,等级二: 20~40,等级三: 10~20,等级四: 5~10,等级五: ≤5"
|
||
if "AK" in df.columns:
|
||
df["AK_DJ"] = df["AK"].apply(lambda x: classify_available_k(x) if pd.notna(x) else np.nan)
|
||
df["AK_DJZY"] = "等级一: >150,等级二: 100~150,等级三: 75~100,等级四: 50~75,等级五: ≤50"
|
||
if "GZCHD" in df.columns:
|
||
df["GZCHD_DJ"] = df["GZCHD"].apply(lambda x: classify_soil_depth(x) if pd.notna(x) else np.nan)
|
||
df["GZCHD_DJZY"] = "等级一: >25,等级二: 20~25,等级三: 15~20,等级四: 10~15,等级五: ≤10"
|
||
if "TRRZ" in df.columns:
|
||
df["TRRZ_DJ"] = df["TRRZ"].apply(lambda x: classify_bulk_density(x) if pd.notna(x) else np.nan)
|
||
df["TRRZ_DJZY"] = "等级一: >1.00~1.20,等级二: 1.20~1.30,等级三: 1.30~1.40,0.90~1.0,等级四: 1.40~1.50,等级五: >1.50,≤0.90"
|
||
if "TN" in df.columns:
|
||
df["TN_DJ"] = df["TN"].apply(lambda x: classify_total_n(x) if pd.notna(x) else np.nan)
|
||
df["TN_DJZY"] = "等级一: >2.0,等级二: 1.5~2.0,等级三: 1.0~1.5,等级四: 0.5~1.0,等级五: ≤0.5"
|
||
if "TP" in df.columns:
|
||
df["TP_DJ"] = df["TP"].apply(lambda x: classify_total_p(x) if pd.notna(x) else np.nan)
|
||
df["TP_DJZY"] = "等级一: >1.5,等级二: 1.0~1.5,等级三: 0.6~1.0,等级四: 0.4~0.6,等级五: ≤0.4"
|
||
if "TK" in df.columns:
|
||
df["TK_DJ"] = df["TK"].apply(lambda x: classify_total_k(x) if pd.notna(x) else np.nan)
|
||
df["TK_DJZY"] = "等级一: >20.0,等级二: 15.0~20.0,等级三: 10.0~15.0,等级四: 5.0~10.0,等级五: ≤5.0"
|
||
if "AFE" in df.columns:
|
||
df["AFE_DJ"] = df["AFE"].apply(lambda x: classify_available_fe(x) if pd.notna(x) else np.nan)
|
||
df["AFE_DJZY"] = "等级一: >20,等级二: 10~20,等级三: 8~10,等级四: 3~8,等级五: ≤3"
|
||
if "AZN" in df.columns:
|
||
df["AZN_DJ"] = df["AZN"].apply(lambda x: classify_available_zn(x) if pd.notna(x) else np.nan)
|
||
df["AZN_DJZY"] = "等级一: >3.0,等级二: 2.0~3.0,等级三: 1.0~2.0,等级四: 0.5~1.0,等级五: ≤0.5"
|
||
if "AMN" in df.columns:
|
||
df["AMN_DJ"] = df["AMN"].apply(lambda x: classify_available_mn(x) if pd.notna(x) else np.nan)
|
||
df["AMN_DJZY"] = "等级一: >30.0,等级二: 20.0~30.0,等级三: 10.0~20.0,等级四: 5.0~10.0,等级五: ≤5.0"
|
||
if "ACU" in df.columns:
|
||
df["ACU_DJ"] = df["ACU"].apply(lambda x: classify_available_cu(x) if pd.notna(x) else np.nan)
|
||
df["ACU_DJZY"] = "等级一: >1.80,等级二: 1.00~1.80,等级三: 0.50~1.00,等级四: 0.2~0.5,等级五: ≤0.2"
|
||
if "AB" in df.columns:
|
||
df["AB_DJ"] = df["AB"].apply(lambda x: classify_available_b(x) if pd.notna(x) else np.nan)
|
||
df["AB_DJZY"] = "等级一: >2.0,等级二: 1.0~2.0,等级三: 0.5~1.0,等级四: 0.2~0.5,等级五: ≤0.2"
|
||
if "AMO" in df.columns:
|
||
df["AMO_DJ"] = df["AMO"].apply(lambda x: classify_available_mo(x) if pd.notna(x) else np.nan)
|
||
df["AMO_DJZY"] = "等级一: >0.20,等级二: 0.15~0.20,等级三: 0.10~0.15,等级四: 0.05~0.10,等级五: ≤0.05"
|
||
if "AS1" in df.columns:
|
||
df["AS1_DJ"] = df["AS1"].apply(lambda x: classify_available_s(x) if pd.notna(x) else np.nan)
|
||
df["AS1_DJZY"] = "等级一: >40.0,等级二: 30.0~40.0,等级三: 20.0~30.0,等级四: 10.0~20.0,等级五: ≤10.0"
|
||
if "ECA" in df.columns:
|
||
df["ECA_DJ"] = df["ECA"].apply(lambda x: classify_exchangeable_ca(x) if pd.notna(x) else np.nan)
|
||
df["ECA_DJZY"] = "等级一: >20,等级二: 15~30.0,等级三: 10.0~15.0,等级四: 5~10.0,等级五: ≤5.0"
|
||
if "EMG" in df.columns:
|
||
df["EMG_DJ"] = df["EMG"].apply(lambda x: classify_exchangeable_mg(x) if pd.notna(x) else np.nan)
|
||
df["EMG_DJZY"] = "等级一: >1.64,等级二: 0.82~1.64,等级三: 0.41~0.82,等级四: 0.21~0.41,等级五: ≤0.21"
|
||
if "TSE" in df.columns:
|
||
df["TSE_DJ"] = df["TSE"].apply(lambda x: classify_total_se(x) if pd.notna(x) else np.nan)
|
||
df["TSE_DJZY"] = "等级一: >3.0,等级二: 0.4~3.0,等级三: 0.17~0.4,等级四:≤0.17"
|
||
if "FL" in df.columns:
|
||
df["FL_DJ"] = df["FL"].apply(lambda x: classify_silt(x) if pd.notna(x) else np.nan)
|
||
df["FL_DJZY"] = "等级一: ≤15,等级二: 15~30,等级三: 30~45,等级四: 45~75,等级五: >75"
|
||
if "NL" in df.columns:
|
||
df["NL_DJ"] = df["NL"].apply(lambda x: classify_clay(x) if pd.notna(x) else np.nan)
|
||
df["NL_DJZY"] = "等级一: ≤15,等级二: 15~25,等级三: 25~45,等级四: 45~65,等级五: >65"
|
||
if "SL" in df.columns:
|
||
df["SL_DJ"] = df["SL"].apply(lambda x: classify_sand(x) if pd.notna(x) else np.nan)
|
||
df["SL_DJZY"] = "等级一: ≤30,等级二: 30~40,等级三: 40~55,等级四: 55~85,等级五: >85"
|
||
if "YXTCHD" in df.columns:
|
||
df["YXTCHD_DJ"] = df["YXTCHD"].apply(lambda x: classify_yxtchd(x) if pd.notna(x) else np.nan)
|
||
df["YXTCHD_DJZY"] = "等级一: >100,等级二: 80~100,等级三: 60~80,等级四: 40~60,等级五: ≤40"
|
||
if "TRZD" in df.columns:
|
||
df["TRZD_DJ"] = df["TRZD"].apply(lambda x: classify_trzd(x) if pd.notna(x) else np.nan)
|
||
df["TRZD_DJZY"] = "粉(砂)质黏壤土: 1,粉(砂)质黏土: 2,粉(砂)质壤土: 3,黏壤土: 4,黏土: 5,壤土: 6,壤质黏土: 7,砂土及壤质砂土: 8,砂质黏壤土: 9,砂质黏土: 10,砂质壤土: 11,重黏土: 12"
|
||
if "DBLSFD" in df.columns:
|
||
df["DBLSFD_DJ"] = df["DBLSFD"].apply(lambda x: classify_lsfd(x) if pd.notna(x) else np.nan)
|
||
df["DBLSFD_DJZY"] = "等级一: =0,等级二: 0~5,等级三: 5.0~15.0,等级四: 15~50,等级五: ≥50"
|
||
|
||
return df
|
||
|
||
def main():
|
||
"""
|
||
主函数:程序入口
|
||
用户需根据实际情况修改以下参数
|
||
"""
|
||
logger = init_logger()
|
||
logger.info("="*50)
|
||
logger.info("土壤属性栅格面积加权统计程序启动")
|
||
logger.info("="*50)
|
||
|
||
# --------------------------
|
||
# 用户配置区域(必须修改!)
|
||
# --------------------------
|
||
# 1. 矢量图斑文件路径(支持Shapefile、GeoPackage等格式)
|
||
# TODO
|
||
VECTOR_PATH = r"F:\@user\missum\Documents\ArcGIS\Projects\MyProject\MyProject.gdb\西畴县耕园林草其他_SpatialJoin" # 示例:"D:/data/土壤图斑.shp"
|
||
|
||
# 2. 土壤属性栅格文件配置(键:属性名称,值:栅格文件路径)
|
||
# 注意:属性名称必须与最终表格列名一致
|
||
# TODO
|
||
RASTER_FILES = {
|
||
# "GZCHD": r"E:\@三普\云南丘北县\基础数据\三普栅格\GZCHD.tif",
|
||
# "TRRZ": r"E:\@三普\云南丘北县\基础数据\三普栅格\TRRZ.tif",
|
||
# "SL": r"E:\@三普\云南丘北县\基础数据\三普栅格\SL.tif",
|
||
# "FL": r"E:\@三普\云南丘北县\基础数据\三普栅格\FL.tif",
|
||
# "NL": r"E:\@三普\云南丘北县\基础数据\三普栅格\NL.tif",
|
||
# "PH": r"E:\@三普\云南丘北县\基础数据\三普栅格\PH.tif",
|
||
# "CEC": r"E:\@三普\云南丘北县\基础数据\三普栅格\CEC.tif",
|
||
# "OM": r"E:\@三普\云南丘北县\基础数据\三普栅格\OM.tif",
|
||
# "TN": r"E:\@三普\云南丘北县\基础数据\三普栅格\TN.tif",
|
||
# "TP": r"E:\@三普\云南丘北县\基础数据\三普栅格\TP.tif",
|
||
# "TK": r"E:\@三普\云南丘北县\基础数据\三普栅格\TK.tif",
|
||
# "AP": r"E:\@三普\云南丘北县\基础数据\三普栅格\AP.tif",
|
||
# "AK": r"E:\@三普\云南丘北县\基础数据\三普栅格\AK.tif",
|
||
# "AFE": r"E:\@三普\云南丘北县\基础数据\三普栅格\AFE.tif",
|
||
# "AZN": r"E:\@三普\云南丘北县\基础数据\三普栅格\AZN.tif",
|
||
# "AMN": r"E:\@三普\云南丘北县\基础数据\三普栅格\AMN.tif",
|
||
# "ACU": r"E:\@三普\云南丘北县\基础数据\三普栅格\ACU.tif",
|
||
# "AB": r"E:\@三普\云南丘北县\基础数据\三普栅格\AB.tif",
|
||
# "AMO": r"E:\@三普\云南丘北县\基础数据\三普栅格\AMO.tif",
|
||
# "AS1": r"E:\@三普\云南丘北县\基础数据\三普栅格\AS1.tif",
|
||
# "ECA": r"E:\@三普\云南丘北县\基础数据\三普栅格\ECA.tif",
|
||
# "EMG": r"E:\@三普\云南丘北县\基础数据\三普栅格\EMG.tif",
|
||
# "YXTCHD": r"E:\@三普\云南丘北县\基础数据\三普栅格\YXTCHD.tif",
|
||
"TRZD": r"E:\@三普\云南西畴县\基础数据\三普栅格\投影后\TRZD.tif",
|
||
# "DBLSFD": r"E:\@三普\云南丘北县\基础数据\三普栅格\LSFD.tif",
|
||
# "TSE": r"E:\@三普\云南丘北县\基础数据\三普栅格\TSE.tif"
|
||
}
|
||
|
||
# 3. 结果输出路径(Excel文件)
|
||
OUTPUT_PATH = r"E:\@三普\@临时文件夹\西畴县TRSX11.shp" # 示例:"D:/result/结果.shp"
|
||
|
||
# --------------------------
|
||
# 程序执行流程(无需修改)
|
||
# --------------------------
|
||
try:
|
||
# 1. 数据验证
|
||
if not validate_data(VECTOR_PATH, RASTER_FILES):
|
||
logger.error("数据验证失败,程序终止")
|
||
return
|
||
|
||
# 2. 执行面积加权统计
|
||
result_gdf = calculate_area_weighted_stats(VECTOR_PATH, RASTER_FILES, OUTPUT_PATH)
|
||
|
||
# 3. 显示结果预览
|
||
# logger.info("\\n结果预览(前3行):")
|
||
# print(result_gdf.head(3).to_string(index=False))
|
||
|
||
logger.info("\\n" + "="*50)
|
||
logger.info("程序执行完成!")
|
||
logger.info(f"结果文件:{OUTPUT_PATH}")
|
||
logger.info("="*50)
|
||
|
||
except Exception as e:
|
||
logger.error(f"程序执行出错:{str(e)}", exc_info=True)
|
||
logger.error("程序异常终止")
|
||
|
||
if __name__ == "__main__":
|
||
# 启动主程序
|
||
main()
|