642 lines
27 KiB
Python
642 lines
27 KiB
Python
# -*- coding: utf-8 -*-
|
||
import os
|
||
import arcpy
|
||
import pandas as pd
|
||
import numpy as np
|
||
from openpyxl import Workbook
|
||
from openpyxl.styles import Font
|
||
from openpyxl.utils import get_column_letter
|
||
from tools.config.arcgis_field_cal_code import codeblock_cal_shfj
|
||
from tools.core.utils.excel_utils import ExcelStyleUtils
|
||
|
||
|
||
|
||
yjdl_order = ["耕地", "园地", "林地", "草地", "其他"]
|
||
ejdl_order = ["水田", "旱地", "水浇地", "果园", "茶园", "橡胶园", "其他园地"]
|
||
|
||
# --- 2. 辅助函数 ---
|
||
# 等级计算
|
||
def get_acidification_degree(delta_ph):
|
||
"""根据ΔpH值判断酸化程度"""
|
||
if pd.isna(delta_ph) or delta_ph == 0:
|
||
return "-"
|
||
# 请根据您的实际分级标准调整这里的阈值
|
||
if delta_ph > 1.0:
|
||
return "重度酸化"
|
||
elif 0.5 < delta_ph <= 1.0:
|
||
return "中度酸化"
|
||
elif 0.3 < delta_ph <= 0.5:
|
||
return "轻度酸化"
|
||
elif 0.1 < delta_ph <= 0.3:
|
||
return "弱酸化"
|
||
else: # dPH < -0.3
|
||
return "其他"
|
||
|
||
# --- 3. 数据处理与分析 均值---
|
||
def process_data_for_table5_7(gdb_path, mean_table_name, sample_table_name):
|
||
"""
|
||
【最终版 v2】: 增加对制图样点数的处理,以支持加权平均计算。
|
||
"""
|
||
print("开始处理数据...")
|
||
|
||
def clean_df(df, columns):
|
||
for col in columns:
|
||
df[col] = df[col].astype(str).str.strip()
|
||
df.replace(['<Null>', 'None', '', '<空>'], np.nan, inplace=True)
|
||
df.dropna(subset=columns, inplace=True)
|
||
return df
|
||
|
||
# --- a. 处理样点数据,计算“样点均值” ---
|
||
print("--> 步骤1: 计算样点均值...")
|
||
sample_table_path = os.path.join(gdb_path, sample_table_name)
|
||
sample_fields = ['XZQMC','YJDL','EJDL', 'dPH']
|
||
df_samples = pd.DataFrame(arcpy.da.TableToNumPyArray(sample_table_path, sample_fields, 'dPH>0.3', skip_nulls=False))
|
||
df_samples = clean_df(df_samples, ['XZQMC','YJDL', 'EJDL'])
|
||
|
||
# 按 YJDL, EJDL 分组,计算 dPH 的均值
|
||
df_sample_means = df_samples.groupby(['XZQMC'])['dPH'].mean().reset_index()
|
||
df_sample_means.rename(columns={'dPH': '样点均值'}, inplace=True)
|
||
print("样点均值计算完成。")
|
||
|
||
# --- b. 处理制图数据,获取“制图均值”和“制图样点数” ---
|
||
print("--> 步骤2: 获取制图均值和样点数...")
|
||
mean_table_path = os.path.join(gdb_path, mean_table_name)
|
||
mean_fields = ['XZQMC', 'MEAN', 'COUNT']
|
||
df_map_data = pd.DataFrame(arcpy.da.TableToNumPyArray(mean_table_path, mean_fields, skip_nulls=False))
|
||
df_map_data = clean_df(df_map_data, ['XZQMC'])
|
||
df_map_data.rename(columns={'MEAN': '制图均值', 'COUNT': '制图样点数'}, inplace=True)
|
||
print("制图数据获取完成。")
|
||
|
||
# --- c. 合并数据 ---
|
||
print("--> 步骤3: 合并数据...")
|
||
df_skeleton = pd.concat([
|
||
df_sample_means[['XZQMC']],
|
||
df_map_data[['XZQMC']]
|
||
]).drop_duplicates().reset_index(drop=True)
|
||
|
||
df_final = pd.merge(df_skeleton, df_sample_means, on=['XZQMC'], how='left')
|
||
# **【核心修改】: 合并整个 df_map_data,而不仅仅是均值列**
|
||
df_final = pd.merge(df_final, df_map_data, on=['XZQMC'], how='left')
|
||
|
||
# --- d. 计算酸化程度 ---
|
||
print("--> 步骤4: 计算酸化程度...")
|
||
# **【核心修改】: 在计算酸化程度之前,先过滤掉不展示的行**
|
||
# 我们只对 dPH 在酸化范围内 ( > 0.3) 的数据感兴趣
|
||
# 但为了计算合计,我们需要保留所有数据,所以这一步只计算,不删除
|
||
df_final['酸化程度_样本'] = df_final['样点均值'].apply(get_acidification_degree)
|
||
df_final['酸化程度_制图'] = df_final['制图均值'].apply(get_acidification_degree)
|
||
|
||
df_final.sort_values(['XZQMC'], inplace=True)
|
||
|
||
print("数据处理流程完成!")
|
||
return df_final
|
||
|
||
|
||
# --- 4. Excel 制表 均值---
|
||
def write_to_excel_table5_7(df, output_path):
|
||
"""
|
||
将处理好的数据写入格式化的 Excel 文件。
|
||
"""
|
||
if df.empty:
|
||
print("警告: 没有数据可以写入 Excel。")
|
||
return
|
||
|
||
print(f"开始生成 Excel 报告到 '{output_path}'...")
|
||
wb = Workbook()
|
||
ws = wb.create_sheet("Mysheet", 0)
|
||
ws.title = "不同土地利用类型pH变化统计"
|
||
|
||
# --- b. 绘制表头 ---
|
||
ws.merge_cells('A1:A2'); ws['A1'] = '乡镇/街道'
|
||
ws.merge_cells('B1:E1'); ws['B1'] = 'ΔpH'
|
||
|
||
ws['B2'] = '样点均值'
|
||
ws['C2'] = '酸化程度'
|
||
ws['D2'] = '制图均值'
|
||
ws['E2'] = '酸化程度'
|
||
|
||
# --- c. 填充数据 ---
|
||
current_row = 3
|
||
|
||
# **【核心修改】: 先对整个DataFrame进行过滤,只保留需要展示的行**
|
||
acid_levels_to_show = ["弱酸化", "轻度酸化", "中度酸化", "重度酸化", "其他"]
|
||
df_to_write = df[
|
||
df['酸化程度_样本'].isin(acid_levels_to_show) | df['酸化程度_制图'].isin(acid_levels_to_show)
|
||
].copy() # 使用 .copy() 避免 SettingWithCopyWarning
|
||
|
||
for _, row_data in df_to_write.iterrows():
|
||
|
||
print(f"正在写入一级地类...")
|
||
|
||
# 写入数据”
|
||
ws.cell(row=current_row, column=1).value = row_data['XZQMC']
|
||
|
||
# 填充样点数据
|
||
sample_mean = row_data.get('样点均值')
|
||
if pd.notna(sample_mean):
|
||
ws.cell(row=current_row, column=2).value = f"{sample_mean:.2f}" if sample_mean > 0.3 else "-"
|
||
ws.cell(row=current_row, column=3).value = row_data.get('酸化程度_样本', '-') if sample_mean > 0.3 else "-"
|
||
else:
|
||
ws.cell(row=current_row, column=2).value = "-"
|
||
ws.cell(row=current_row, column=3).value = "-"
|
||
|
||
# 填充制图数据
|
||
map_mean = row_data.get('制图均值')
|
||
if pd.notna(map_mean):
|
||
ws.cell(row=current_row, column=4).value = f"{map_mean:.2f}" if map_mean > 0.3 else "-"
|
||
ws.cell(row=current_row, column=5).value = row_data.get('酸化程度_制图', '-') if map_mean > 0.3 else "-"
|
||
else:
|
||
ws.cell(row=current_row, column=4).value = "-"
|
||
ws.cell(row=current_row, column=5).value = "-"
|
||
|
||
current_row += 1
|
||
|
||
# --- a. 定义样式 ---
|
||
header_font = Font(name='等线', size=11, bold=True)
|
||
|
||
# --- d. 应用样式和调整列宽 ---
|
||
max_col_letter = get_column_letter(ws.max_column)
|
||
if current_row > 1: # 确保有数据才应用样式
|
||
ExcelStyleUtils.set_style(ws, f'A1:{max_col_letter}{current_row-1}')
|
||
ExcelStyleUtils.set_style(ws, f'A1:{max_col_letter}2', header_font)
|
||
|
||
print("正在自动调整列宽...")
|
||
|
||
# 设置列宽
|
||
ExcelStyleUtils.auto_adjust_column_width(ws)
|
||
|
||
# --- e. 保存文件 ---
|
||
wb.save(output_path)
|
||
print("Excel 报告生成成功!")
|
||
|
||
|
||
# --- 2. 数据处理与分析 面积 各乡镇---
|
||
def process_data_for_table5_4(gdb_path, area_table_name, target_area_dict):
|
||
"""
|
||
【最终修正版 v2】: 先建立统一的层级结构,再分别合并统计结果。
|
||
"""
|
||
print("【最终修正版 v2】开始处理数据...")
|
||
|
||
def clean_df(df, columns):
|
||
for col in columns:
|
||
df[col] = df[col].astype(str).str.strip()
|
||
df.replace(['<Null>', 'None', '', '<空>'], np.nan, inplace=True)
|
||
df.dropna(subset=columns, inplace=True)
|
||
return df
|
||
|
||
# --- a. 独立统计面积数据 ---
|
||
print("--> 步骤1: 独立统计面积数据...")
|
||
area_table_path = os.path.join(gdb_path, area_table_name)
|
||
df_area = pd.DataFrame(arcpy.da.TableToNumPyArray(area_table_path, ['XZQMC', 'SHFJ', 'AREA'], skip_nulls=False))
|
||
df_area = clean_df(df_area, ['XZQMC'])
|
||
|
||
df_final = pd.DataFrame()
|
||
if not df_area.empty:
|
||
# 计算平差系数
|
||
target_shfj_areas = target_area_dict.groupby(['SHFJ'])['AREA_MU'].sum().reset_index()
|
||
original_shfj_areas = df_area.groupby(['SHFJ'])['AREA'].sum().reset_index()
|
||
original_shfj_areas['AREA_MU'] = original_shfj_areas['AREA'] * 0.0015
|
||
|
||
adjustment_factors = []
|
||
for index, row in original_shfj_areas.iterrows():
|
||
shfj = row['SHFJ']
|
||
area_mu = row['AREA_MU']
|
||
adjustment_factor = target_shfj_areas[target_shfj_areas['SHFJ'] == shfj]['AREA_MU'].values[0] / area_mu
|
||
adjustment_factors.append({
|
||
'SHFJ': shfj,
|
||
'平差系数':adjustment_factor
|
||
})
|
||
|
||
|
||
factor_df = pd.DataFrame(adjustment_factors)
|
||
|
||
df_sh_area = df_area.merge(factor_df[['SHFJ', '平差系数']], on='SHFJ')
|
||
|
||
df_sh_area['制图面积_亩'] = df_sh_area['AREA'] * 0.0015 * df_sh_area['平差系数']
|
||
ts_total_area = df_sh_area.groupby(['XZQMC'])['制图面积_亩'].transform('sum')
|
||
df_sh_area['面积占比'] = (df_sh_area['制图面积_亩'] / ts_total_area) * 100
|
||
df_area_stats = df_sh_area.pivot_table(
|
||
index=['XZQMC'], columns='SHFJ', values=['制图面积_亩', '面积占比'], fill_value=0
|
||
).reset_index()
|
||
df_area_stats.columns = [f'{col[0]}_{col[1]}'.strip('_') if col[1] else col[0] for col in df_area_stats.columns]
|
||
|
||
df_final = df_area_stats
|
||
|
||
print("--> 步骤2: 计算酸化面积合计...")
|
||
|
||
# 定义属于酸化类别的面积列
|
||
acidic_area_cols = [
|
||
'制图面积_亩_轻度酸化',
|
||
'制图面积_亩_中度酸化',
|
||
'制图面积_亩_重度酸化'
|
||
]
|
||
|
||
# 确保这些列存在于DataFrame中,不存在的列用0代替
|
||
for col in acidic_area_cols:
|
||
if col not in df_final.columns:
|
||
df_final[col] = 0
|
||
|
||
# 将这三列相加,得到合计值
|
||
df_final['酸化面积合计_亩'] = df_final[acidic_area_cols].sum(axis=1)
|
||
|
||
# --- d. 最后清理和构建映射 ---
|
||
df_final.fillna(0, inplace=True)
|
||
|
||
print("数据处理流程完成!")
|
||
return df_final
|
||
|
||
# --- 3. Excel 制表 面积---
|
||
def write_to_excel_table5_4(df, output_path):
|
||
"""
|
||
【最终修正版】: 将处理好的数据写入格式化的 Excel 文件。
|
||
"""
|
||
if df.empty:
|
||
print("警告: 没有数据可以写入 Excel,将创建一个空的报告。")
|
||
wb = Workbook()
|
||
ws = wb.create_sheet("Mysheet", 0)
|
||
ws.title = "不同乡镇酸化面积统计"
|
||
ws['A1'] = "没有有效的统计数据。"
|
||
wb.save(output_path)
|
||
return
|
||
|
||
print(f"开始生成 Excel 报告到 '{output_path}'...")
|
||
wb = Workbook()
|
||
ws = wb.create_sheet("Mysheet", 0)
|
||
ws.title = "不同乡镇酸化面积统计"
|
||
|
||
# --- b. 绘制表头 (不变) ---
|
||
ws.merge_cells('A1:A2'); ws['A1'] = '乡镇/街道'
|
||
|
||
acid_levels = ['弱酸化', '轻度酸化', '中度酸化', '重度酸化', '其他']
|
||
# acid_level_headers = ['0.1<ΔpH≤0.3', '0.3<ΔpH≤0.5', '0.5<ΔpH≤1.0', 'ΔpH>1.0', '其他']
|
||
# all_possible_levels = ['碱化', '未酸化', '轻度酸化', '中度酸化', '重度酸化']
|
||
acid_level_headers = ['弱酸化(0.1<ΔpH≤0.3)','轻度酸化(0.3<ΔpH≤0.5)', '中度酸化(0.5<ΔpH≤1.0)', '重度酸化(ΔpH>1.0)', '其他(未酸化)']
|
||
|
||
col_start = 2
|
||
for header in acid_level_headers:
|
||
ws.merge_cells(start_row=1, start_column=col_start, end_row=1, end_column=col_start + 1)
|
||
ws.cell(row=1, column=col_start).value = header
|
||
ws.cell(row=2, column=col_start).value = '面积/亩'
|
||
ws.cell(row=2, column=col_start + 1).value = '占比/%'
|
||
col_start += 2
|
||
|
||
# 增加合计列的表头**
|
||
total_col = col_start # 记录合计列的列号
|
||
ws.merge_cells(start_row=1, start_column=total_col, end_row=2, end_column=total_col)
|
||
ws.cell(row=1, column=total_col).value = '酸化面积合计'
|
||
|
||
# --- c. 填充数据 (完全重构的逻辑) ---
|
||
current_row = 3
|
||
|
||
# **【核心修改】: 不再需要 group_yl_df,直接遍历整个 df**
|
||
# 假设 df 已经按 XZQMC 排序(如果需要的话)
|
||
df_sorted = df.sort_values('XZQMC').reset_index(drop=True)
|
||
|
||
for index, row_data in df_sorted.iterrows():
|
||
ws.cell(row=current_row, column=1).value = row_data['XZQMC']
|
||
|
||
col_start = 2
|
||
for level in acid_levels:
|
||
area_col = f'制图面积_亩_{level}'
|
||
area_pct_col = f'面积占比_{level}'
|
||
area_val = row_data.get(area_col, 0)
|
||
area_pct_val = row_data.get(area_pct_col, 0)
|
||
|
||
ws.cell(row=current_row, column=col_start).value = f"{area_val:.0f}" if area_val > 0 else "-"
|
||
ws.cell(row=current_row, column=col_start + 1).value = f"{area_pct_val:.2f}%" if area_val > 0 else "-"
|
||
col_start += 2
|
||
|
||
# **【核心修改】: 填充酸化面积合计列的值**
|
||
total_area_val = row_data.get('酸化面积合计_亩', 0)
|
||
ws.cell(row=current_row, column=total_col).value = f"{total_area_val:.0f}" if total_area_val > 0 else "-"
|
||
|
||
current_row += 1
|
||
|
||
# **(可选) 增加一个所有乡镇的“总合计”行**
|
||
# print("--> 计算并写入总合计行...")
|
||
# ws.cell(row=current_row, column=1).value = '总合计'
|
||
|
||
# col_start = 2
|
||
# for level in acid_levels:
|
||
# area_col = f'制图面积_亩_{level}'
|
||
# area_sum = df_sorted.get(area_col, 0).sum()
|
||
# # 总合计行的占比是相对于所有乡镇的总面积
|
||
# grand_total_area = df_sorted[[f'制图面积_亩_{lvl}' for lvl in all_possible_levels if f'制图面积_亩_{lvl}' in df_sorted]].sum().sum()
|
||
# area_perc = (area_sum / grand_total_area * 100) if grand_total_area > 0 else 0
|
||
|
||
# ws.cell(row=current_row, column=col_start).value = f"{area_sum:.2f}" if area_sum > 0 else "-"
|
||
# ws.cell(row=current_row, column=col_start + 1).value = f"{area_perc:.2f}" if area_sum > 0 else "-"
|
||
# col_start += 2
|
||
|
||
# grand_total_acidic_area = df_sorted['酸化面积合计_亩'].sum()
|
||
# ws.cell(row=current_row, column=total_col).value = f"{grand_total_acidic_area:.2f}" if grand_total_acidic_area > 0 else "-"
|
||
# current_row += 1
|
||
|
||
# --- a. 定义样式 (不变) ---
|
||
header_font = Font(name='等线', size=11, bold=True)
|
||
|
||
# --- d. 应用样式和调整列宽 (最终健壮版) ---
|
||
max_col_letter = get_column_letter(ws.max_column)
|
||
if current_row > 1: # 确保有数据才应用样式
|
||
ExcelStyleUtils.set_style(ws, f'A1:{max_col_letter}{current_row-1}')
|
||
ExcelStyleUtils.set_style(ws, f'A1:{max_col_letter}2', header_font)
|
||
|
||
print("正在自动调整列宽...")
|
||
# 设置列宽
|
||
ExcelStyleUtils.auto_adjust_column_width(ws)
|
||
|
||
# --- e. 保存文件 ---
|
||
wb.save(output_path)
|
||
print("Excel 报告生成成功!")
|
||
|
||
# 步骤5.3: 生成表5.3 - 总表数据处理
|
||
def process_data_for_table5_2(gdb_path, area_table_name, sample_table_name, target_area_dict:pd.DataFrame):
|
||
def clean_df(df, columns):
|
||
for col in columns:
|
||
df[col] = df[col].astype(str).str.strip()
|
||
df.replace(['<Null>', 'None', '', '<空>'], np.nan, inplace=True)
|
||
df.dropna(subset=columns, inplace=True)
|
||
return df
|
||
|
||
# --- a. 从两个表中提取并建立唯一的 (YJDL, EJDL) 层级结构 "骨架" ---
|
||
print("--> 步骤1: 建立统一的层级结构...")
|
||
sample_table_path = os.path.join(gdb_path, sample_table_name)
|
||
area_table_path = os.path.join(gdb_path, area_table_name)
|
||
|
||
|
||
# --- b. 独立统计样点数据 ---
|
||
print("--> 步骤2: 独立统计样点数据...")
|
||
df_samples = pd.DataFrame(arcpy.da.TableToNumPyArray(sample_table_path, ['XZQMC', 'dPH'], skip_nulls=False))
|
||
df_samples = clean_df(df_samples, ['XZQMC'])
|
||
|
||
if not df_samples.empty:
|
||
bins = [-np.inf, 0.1, 0.3, 0.5, 1.0, np.inf]
|
||
labels = ["其他", "弱酸化", "轻度酸化", "中度酸化", "重度酸化"]
|
||
df_samples['SHFJ'] = pd.cut(df_samples['dPH'], bins=bins, labels=labels, right=True)
|
||
sample_counts = df_samples.groupby(['SHFJ'], observed=False).size().reset_index(name='样点数')
|
||
sample_counts = sample_counts.merge(df_samples.groupby(['SHFJ'], observed=False)['dPH'].mean(), on='SHFJ')
|
||
ts_total_samples = sample_counts['样点数'].sum()
|
||
sample_counts['样点占比'] = (sample_counts['样点数'] / ts_total_samples) * 100
|
||
# print(sample_counts)
|
||
|
||
# --- c. 独立统计面积数据 ---
|
||
print("--> 步骤3: 独立统计面积数据...")
|
||
df_area = pd.DataFrame(arcpy.da.TableToNumPyArray(area_table_path, ['XZQMC', 'SHFJ', 'AREA'], skip_nulls=False))
|
||
df_area = clean_df(df_area, ['XZQMC'])
|
||
|
||
if not df_area.empty:
|
||
# 计算平差系数
|
||
target_shfj_areas = target_area_dict.groupby(['SHFJ'])['AREA_MU'].sum().reset_index()
|
||
original_shfj_areas = df_area.groupby(['SHFJ'])['AREA'].sum().reset_index()
|
||
original_shfj_areas['AREA_MU'] = original_shfj_areas['AREA'] * 0.0015
|
||
|
||
adjustment_factors = []
|
||
for index, row in original_shfj_areas.iterrows():
|
||
shfj = row['SHFJ']
|
||
area_mu = row['AREA_MU']
|
||
adjustment_factor = target_shfj_areas[target_shfj_areas['SHFJ'] == shfj]['AREA_MU'].values[0] / area_mu
|
||
adjustment_factors.append({
|
||
'SHFJ': shfj,
|
||
'平差系数':adjustment_factor
|
||
})
|
||
|
||
|
||
factor_df = pd.DataFrame(adjustment_factors)
|
||
|
||
df_sh_area = df_area.merge(factor_df[['SHFJ', '平差系数']], on='SHFJ')
|
||
|
||
df_sh_area['制图面积_亩'] = df_sh_area['AREA'] * 0.0015 * df_sh_area['平差系数']
|
||
df_area_counts = df_sh_area.groupby(['SHFJ'], observed=False)[['制图面积_亩']].sum()
|
||
ts_total_area = df_area_counts['制图面积_亩'].sum()
|
||
df_area_counts['面积占比'] = (df_area_counts['制图面积_亩'] / ts_total_area) * 100
|
||
|
||
df_final = pd.merge(sample_counts, df_area_counts, on=['SHFJ'], how='left')
|
||
|
||
# # --- d. 最后清理和构建映射 ---
|
||
df_final.fillna(0, inplace=True)
|
||
|
||
return df_final
|
||
|
||
# --- 3. Excel 制表 总表---
|
||
def write_to_excel_table5_2(df, df_mean, output_path):
|
||
"""
|
||
【最终修正版】: 将处理好的数据写入格式化的 Excel 文件。
|
||
"""
|
||
if df.empty:
|
||
print("警告: 没有数据可以写入 Excel,将创建一个空的报告。")
|
||
wb = Workbook()
|
||
ws = wb.create_sheet("Mysheet", 0)
|
||
ws['A1'] = "没有有效的统计数据。"
|
||
wb.save(output_path)
|
||
return
|
||
|
||
print(f"开始生成 Excel 报告到 '{output_path}'...")
|
||
wb = Workbook()
|
||
ws = wb.create_sheet("Mysheet", 0)
|
||
ws.title = "行政区酸化程度等级分布及占比"
|
||
|
||
# --- b. 绘制表头 (不变) ---
|
||
ws.merge_cells('A1:B1'); ws['A1'] = '酸化程度'
|
||
ws.merge_cells('C1:D1'); ws['C1'] = '样点统计'
|
||
ws.merge_cells('E1:F1'); ws['E1'] = '制图统计'
|
||
ws.merge_cells('A8:B8'); ws['A8'] = '总计'
|
||
ws.merge_cells('A9:B9'); ws['A9'] = '全县酸化样点ΔpH 均值'
|
||
ws.merge_cells('A10:B10'); ws['A10'] = '全县酸化制图ΔpH 均值'
|
||
|
||
ws['A2'] = '分级'; ws['B2'] = '值域'
|
||
ws['C2'] = '数量/个'; ws['D2'] = '占比'
|
||
ws['E2'] = '面积/亩'; ws['F2'] = '占比'
|
||
|
||
acid_levels = ['弱酸化', '轻度酸化', '中度酸化', '重度酸化', '其他']
|
||
acid_level_headers = ['0.1<ΔpH≤0.3', '0.3<ΔpH≤0.5', '0.5<ΔpH≤1.0', 'ΔpH>1.0', '未酸化']
|
||
|
||
# --- c. 填充数据 ---
|
||
current_row = 3
|
||
|
||
# 1. 遍历该一级地类下的所有“二级地类”并写入数据
|
||
for index,level in enumerate(acid_levels):
|
||
ws.cell(row=current_row, column=1).value = level
|
||
ws.cell(row=current_row, column=2).value = acid_level_headers[index]
|
||
|
||
# 在子集中查找当前二级地类的数据行
|
||
row_data = df[df['SHFJ'] == level]
|
||
|
||
# --- 填充单元格的逻辑开始 ---
|
||
col_start = 3 # 从第 C 列开始填充
|
||
|
||
# 检查是否找到了该土属的数据
|
||
if not row_data.empty:
|
||
data_series = row_data.iloc[0]
|
||
|
||
# 1. 构建要从 data_series 中查找的列名
|
||
sample_col = f'样点数'
|
||
sample_pct_col = f'样点占比'
|
||
area_col = f'制图面积_亩'
|
||
area_pct_col = f'面积占比'
|
||
|
||
# 2. 从 data_series 中安全地获取值
|
||
sample_val = data_series.get(sample_col, 0)
|
||
sample_pct_val = data_series.get(sample_pct_col, 0)
|
||
area_val = data_series.get(area_col, 0)
|
||
area_pct_val = data_series.get(area_pct_col, 0)
|
||
|
||
|
||
# 3. 将获取到的值填入单元格
|
||
ws.cell(row=current_row, column=col_start).value = f"{sample_val:.0f}" if sample_val > 0 else "-"
|
||
# 占比/%
|
||
ws.cell(row=current_row, column=col_start + 1).value = f"{sample_pct_val:.2f}%" if sample_val > 0 else "-"
|
||
# 制图面积/亩
|
||
ws.cell(row=current_row, column=col_start + 2).value = f"{area_val:.0f}" if area_val > 0 else "-"
|
||
# 占比/%
|
||
ws.cell(row=current_row, column=col_start + 3).value = f"{area_pct_val:.2f}%" if area_val > 0 else "-"
|
||
|
||
# 移动到下一个酸化等级的起始列
|
||
col_start += 2
|
||
else:
|
||
for _ in range(4):
|
||
ws.cell(row=current_row, column=col_start).value = "-"
|
||
col_start += 1
|
||
|
||
current_row += 1
|
||
|
||
# 合计单元格填充
|
||
mask = df["SHFJ"].isin(acid_levels)
|
||
df_acid = df[mask]
|
||
weighted_avg = (df_acid["dPH"] * df_acid["样点数"]).sum() / df_acid["样点数"].sum()
|
||
|
||
mean_msk = df_mean["酸化程度_制图"].isin(acid_levels)
|
||
df_mean_acid = df_mean[mean_msk]
|
||
weighted_mean = (df_mean_acid["制图均值"] * df_mean_acid["制图样点数"]).sum() / df_mean_acid["制图样点数"].sum()
|
||
|
||
ws.merge_cells('C9:F9')
|
||
ws.merge_cells('C10:F10')
|
||
ws['C8'] = df[df['SHFJ'].isin(acid_levels)]['样点数'].sum()
|
||
ws['D8'] = f"{df[df['SHFJ'].isin(acid_levels)]['样点占比'].sum():.2f}%"
|
||
ws['E8'] = f"{df[df['SHFJ'].isin(acid_levels)]['制图面积_亩'].sum():.0f}"
|
||
ws['F8'] = f"{df[df['SHFJ'].isin(acid_levels)]['面积占比'].sum():.2f}%"
|
||
ws['C9'] = f"{weighted_avg:.2f}" # type: ignore
|
||
ws['C10'] = f"{weighted_mean:.2f}"
|
||
|
||
# --- a. 定义样式 (不变) ---
|
||
header_font = Font(name='宋体', size=11)
|
||
|
||
# --- d. 应用样式和调整列宽 (最终健壮版) ---
|
||
if current_row > 1: # 确保有数据才应用样式
|
||
ExcelStyleUtils.set_style(ws, f'A1:F10')
|
||
ExcelStyleUtils.set_style(ws, f'A1:F2', header_font)
|
||
|
||
print("正在自动调整列宽...")
|
||
|
||
# 设置列宽
|
||
ExcelStyleUtils.auto_adjust_column_width(ws)
|
||
|
||
# --- e. 保存文件 ---
|
||
wb.save(output_path)
|
||
print("Excel 报告生成成功!")
|
||
|
||
|
||
def main(gdb_path, xzq_features, ph_features, dltb_features, sh_ph_tif, output_path,target_areas_dict:dict):
|
||
try:
|
||
# --- 1. 用户配置 ---
|
||
# 输出配置
|
||
output_excel_path = os.path.join(output_path,"乡镇街道酸化统计表.xlsx") # 生成的Excel报告文件路径
|
||
|
||
# 设置工作空间和变量
|
||
arcpy.env.workspace = gdb_path
|
||
arcpy.env.overwriteOutput = True
|
||
|
||
sample_table_name = "历史样点PH信息_Table" # 图2: 样点信息表名
|
||
in_zone_feature = xzq_features # 规划分区图层
|
||
in_class_feature = ph_features # 已重分类好的酸化PH图层
|
||
dltb_class_feature = dltb_features
|
||
in_value_raster = sh_ph_tif # 赋值栅格
|
||
out_feature_class = "最小面积统计单元"
|
||
out_table_area = r"行政区划_酸化面积表" # 输出的交集表名
|
||
out_table_mean = r"行政区划_酸化均值表" # 输出的均值表名
|
||
|
||
print("开始处理数据...")
|
||
|
||
if not arcpy.Exists(out_feature_class):
|
||
# 判断输入表是否存在SHFJ字段
|
||
try:
|
||
arcpy.management.CalculateField(in_class_feature, "SHFJ", "calculate_shfj(!gridcode!)", "PYTHON3", codeblock_cal_shfj)
|
||
except Exception as e:
|
||
print(f"计算SHFJ字段时发生错误: {e}")
|
||
|
||
arcpy.analysis.Intersect(
|
||
in_features=[dltb_class_feature, in_class_feature],
|
||
out_feature_class=out_feature_class,
|
||
join_attributes="ALL",
|
||
output_type="INPUT"
|
||
)
|
||
|
||
if not arcpy.Exists(out_table_area):
|
||
# 1.用arcpy.analysis.TabulateIntersection进行交集制表
|
||
arcpy.analysis.TabulateIntersection(
|
||
in_zone_feature,
|
||
["XZQMC"],
|
||
out_feature_class,
|
||
out_table_area,
|
||
"SHFJ",
|
||
out_units="SQUARE_METERS",
|
||
)
|
||
|
||
if not arcpy.Exists(out_table_mean):
|
||
# 2.用arcpy.sa.ZonalStatisticsAsTable进行区域统计
|
||
arcpy.sa.ZonalStatisticsAsTable(
|
||
in_zone_feature, "XZQMC", in_value_raster, out_table_mean, "DATA", "MEAN"
|
||
)
|
||
|
||
# 计算按地类平差后的各酸化等级面积
|
||
if arcpy.Exists(out_feature_class):
|
||
df = pd.DataFrame(arcpy.da.TableToNumPyArray(out_feature_class, ["YJDL", "SHFJ", "Shape_Area"]))
|
||
df_area = df.groupby(["YJDL", "SHFJ"]).agg({"Shape_Area": "sum"}).reset_index()
|
||
|
||
yjdl_area = df_area.groupby(['YJDL'])['Shape_Area'].sum().reset_index()
|
||
|
||
landuse_types = {'耕地':'01', '园地':'02', '林地':'03', '草地':'04', '其他':'12'}
|
||
adjustment_factors = []
|
||
for _, row in yjdl_area.iterrows():
|
||
yjdl = row['YJDL']
|
||
original_total = row['Shape_Area'] * 0.0015
|
||
target_total = target_areas_dict.get(landuse_types[yjdl], original_total)
|
||
adjustment_factor = target_total / original_total
|
||
|
||
adjustment_factors.append({
|
||
'YJDL': yjdl,
|
||
'平差系数': adjustment_factor
|
||
})
|
||
|
||
factor_df = pd.DataFrame(adjustment_factors)
|
||
|
||
df_with_factors = df_area.merge(factor_df[['YJDL', '平差系数']], on='YJDL')
|
||
df_with_factors['AREA_MU'] = df_with_factors['Shape_Area'] * df_with_factors['平差系数'] * 0.0015
|
||
|
||
# print(df_with_factors)
|
||
|
||
# 生成表5.4的面积统计Excel报告
|
||
final_area_dataframe = process_data_for_table5_4(gdb_path, out_table_area, df_with_factors)
|
||
write_to_excel_table5_4(final_area_dataframe, output_excel_path)
|
||
|
||
# 生成表5.3的均值统计Excel报告
|
||
final_mean_dataframe = process_data_for_table5_7(gdb_path, out_table_mean, sample_table_name)
|
||
write_to_excel_table5_7(final_mean_dataframe, output_excel_path.replace(".xlsx", "_mean.xlsx"))
|
||
|
||
# 生成总表5.2的统计Excel报告
|
||
final_dataframe = process_data_for_table5_2(gdb_path, out_table_area, sample_table_name, df_with_factors)
|
||
write_to_excel_table5_2(final_dataframe, final_mean_dataframe, output_excel_path.replace(".xlsx", "_total.xlsx"))
|
||
|
||
return df_with_factors
|
||
except Exception as e:
|
||
print(f"\n处理过程中发生严重错误: {e}")
|
||
import traceback
|
||
|
||
traceback.print_exc()
|
||
finally:
|
||
import gc
|
||
gc.collect()
|
||
|
||
# --- 4. 主程序入口 ---
|
||
# if __name__ == "__main__":
|
||
# main()
|