// ================= 1. 基础配置与数据源 =================
var CHIRPS = ee.ImageCollection("UCSB-CHG/CHIRPS/PENTAD"),
soilData = ee.Image("OpenLandMap/SOL/SOL_TEXTURE-CLASS_USDA-TT_M/v02"),
DEM = ee.Image("USGS/SRTMGL1_003"),
aoi = ee.FeatureCollection("projects/ee-20241200080/assets/xiangjiang");
var analysisYear = 2020;
var targetScale = 250;
var exportRootFolder = "Lishui_" + analysisYear;
var factorFolder = "RUSLE_Factors_Lishui";
var modulusFolder = "Erosion_Modulus_Lishui";
Map.centerObject(aoi, 9);
Map.addLayer(aoi, {color: 'FF0000', fillColor: '00000000'}, '澧水流域边界');
var areaHectares = ee.Image.pixelArea().divide(10000).rename('area_ha');
// ================= 2. 先计算所有RUSLE因子 =================
// K因子计算
function calculateK_Corrected(soilData, aoi) {
var soilClip = soilData.clip(aoi);
var K = soilClip.expression(
"b('b0') == 1 ? 0.035 : b('b0') == 2 ? 0.040 : " +
"b('b0') == 3 ? 0.045 : b('b0') == 4 ? 0.050 : " +
"b('b0') == 5 ? 0.035 : b('b0') == 6 ? 0.048 : " +
"b('b0') == 7 ? 0.055 : b('b0') == 8 ? 0.055 : " +
"b('b0') == 9 ? 0.050 : b('b0') == 10 ? 0.025 : " +
"b('b0') == 11 ? 0.010 : 0.04",
{'b0': soilClip.select('b0')}
).rename('K');
return K.clip(aoi).unmask(0.045);
}
var K = calculateK_Corrected(soilData, aoi);
// ================= R 因子计算(修正版 - 使用PENTAD数据正确聚合) =================
var months = ee.List.sequence(1, 12);
var monthlyR = months.map(function(month) {
month = ee.Number(month);
var startDate = ee.Date.fromYMD(analysisYear, month, 1);
var endDate = startDate.advance(1, 'month');
// 使用PENTAD数据,但正确聚合为月数据
var monthlyPrecip = CHIRPS.filterDate(startDate, endDate)
.select('precipitation')
.sum() // 将候数据累加为月降雨量
.clip(aoi);
// 章文波公式
var Ri = monthlyPrecip.expression(
'0.0585 * pow(P, 1.56)', {
'P': monthlyPrecip
}
).rename('R');
return Ri.set('month', month);
});
var R_monthly = ee.ImageCollection(monthlyR);
var R = R_monthly.sum().rename('R');
// LS因子计算
var demClip = DEM.clip(aoi).resample('bilinear')
.reproject({crs: 'EPSG:4326', scale: targetScale});
var slopeDeg = ee.Terrain.slope(demClip);
var slopeRad = slopeDeg.multiply(Math.PI).divide(180);
var flowAcc = ee.Image("WWF/HydroSHEDS/15ACC").clip(aoi)
.resample('bilinear').reproject({crs: 'EPSG:4326', scale: targetScale});
var flowArea = flowAcc.multiply(ee.Number(targetScale).pow(2));
var slopeLength = flowArea.sqrt().min(300);
var mExp = slopeRad.expression(
"slope < 0.05 ? 0.2 : slope < 0.10 ? 0.3 : slope < 0.15 ? 0.4 : slope < 0.25 ? 0.5 : 0.6",
{'slope': slopeRad}
);
var L = slopeLength.divide(22.13).pow(mExp).rename('L').unmask(1);
var S = slopeRad.expression(
"slope < 0.05 ? 10.8 * sin(slope) + 0.03 : " +
"slope < 0.10 ? 16.8 * sin(slope) - 0.30 : " +
"slope < 0.15 ? 21.9 * sin(slope) - 0.70 : " +
"slope < 0.25 ? 31.6 * sin(slope) - 1.50 : " +
"45.2 * sin(slope) - 2.50",
{'slope': slopeRad}
).rename('S').unmask(0.05);
var LS = L.multiply(S).rename('LS')
.updateMask(L.gt(0).and(S.gt(0)))
.clip(aoi).unmask(0.1);
// C因子计算 - 优化参数
var modisLulc = ee.ImageCollection("MODIS/006/MCD12Q1")
.filterDate(ee.Date.fromYMD(analysisYear, 1, 1), ee.Date.fromYMD(analysisYear, 12, 31))
.first().select('LC_Type1').clip(aoi)
.resample('bilinear').reproject({crs: 'EPSG:4326', scale: targetScale});
var modisNDVI = ee.ImageCollection('MODIS/006/MOD13Q1')
.filterDate(ee.Date.fromYMD(analysisYear, 1, 1), ee.Date.fromYMD(analysisYear, 12, 31))
.filterBounds(aoi).select('NDVI');
var monthlyC = ee.List.sequence(1, 12).map(function(month) {
month = ee.Number(month);
var monthStart = ee.Date.fromYMD(analysisYear, month, 1);
var monthEnd = monthStart.advance(1, 'month');
var monthNdviCol = modisNDVI.filterDate(monthStart, monthEnd);
var monthNdvi = ee.Algorithms.If(
monthNdviCol.size().gt(0),
monthNdviCol.mean().clip(aoi),
modisNDVI.filterDate(monthStart.advance(-1, 'month'), monthEnd.advance(1, 'month')).mean().clip(aoi)
);
monthNdvi = ee.Image(monthNdvi).multiply(0.0001).unmask(0.3);
var FVC = monthNdvi.subtract(0.05).divide(0.75).clamp(0, 1);
var cNdvi = FVC.expression("exp(-2.0 * fvc)", {'fvc': FVC}).clamp(0.001, 1); // 调整系数
var cLulc = modisLulc.remap(
ee.List.sequence(1, 17),
[0.002, 0.003, 0.004, 0.006, 0.005, 0.020, 0.05, 0.10, 0.15, 0.22, 0.015, 0.45, 0.65, 0.35, 0.001, 0.001, 0.75],
0.35
);
return cNdvi.min(cLulc).clamp(0.001, 1).rename('C').set('month', month);
});
var C_monthly = ee.ImageCollection(monthlyC);
var C = C_monthly.mean().rename('C').clip(aoi).unmask(0.15); // 调整默认值
// P因子计算 - 优化参数
var lulcBaseP = ee.Dictionary({
1: 0.02, 2: 0.02, 3: 0.02, 4: 0.02, 5: 0.02,
6: 0.035, 7: 0.09, 8: 0.15, 9: 0.22, 10: 0.28,
11: 0.001, 12: 0.65, 13: 0.90, 14: 0.45, 15: 0.001,
16: 0.001, 17: 0.65
});
var monthlyAdjust = ee.List([1.4, 1.35, 1.3, 1.25, 1.2, 1.1, 1.0, 0.9, 0.85, 0.8, 0.75, 0.7]); // 调整月度系数
var monthlyP = ee.List.sequence(1, 12).map(function(month) {
month = ee.Number(month);
var monthStart = ee.Date.fromYMD(analysisYear, month, 1);
var monthEnd = monthStart.advance(1, 'month');
var monthNdviCol = modisNDVI.filterDate(monthStart, monthEnd);
var monthNdvi = ee.Algorithms.If(
monthNdviCol.size().gt(0),
monthNdviCol.mean().clip(aoi),
modisNDVI.filterDate(monthStart.advance(-1, 'month'), monthEnd.advance(1, 'month')).mean().clip(aoi)
);
monthNdvi = ee.Image(monthNdvi).multiply(0.0001).unmask(0.3);
var FVC = monthNdvi.subtract(0.05).divide(0.75).clamp(0, 1).pow(1.5);
var baseP = modisLulc.remap(ee.List.sequence(1, 17), lulcBaseP.values(), 0.6); // 调整默认值
var adjust = ee.Image.constant(monthlyAdjust.get(month.subtract(1)));
var slopeAdjustedP = baseP.multiply(
ee.Image(1.0).expression(
"1.0 * (slope < 8 ? 0.8 : slope < 20 ? 1.0 : slope < 35 ? 1.4 : 2.0)",
{'slope': slopeDeg}
)
);
return slopeAdjustedP.multiply(adjust)
.multiply(ee.Image(1).subtract(FVC).add(0.25)) // 调整系数
.clamp(0.15, 1.0)
.rename('P')
.set('month', month);
});
var P_monthly = ee.ImageCollection(monthlyP);
var P = P_monthly.mean().rename('P').clip(aoi).unmask(0.35); // 调整默认值
// ================= 3. 侵蚀模数计算 =================
function getMonthName(monthNum) {
var monthNames = ee.List(['一月', '二月', '三月', '四月', '五月', '六月',
'七月', '八月', '九月', '十月', '十一月', '十二月']);
return ee.String(monthNames.get(ee.Number(monthNum).subtract(1)));
}
var K_250m = K.resample('bilinear').reproject({crs: 'EPSG:4326', scale: targetScale});
var LS_250m = LS.resample('bilinear').reproject({crs: 'EPSG:4326', scale: targetScale});
var monthlyErosionModulus = ee.List.sequence(1, 12).map(function(month) {
month = ee.Number(month);
var monthFilter = ee.Filter.eq('month', month);
var monthR = R_monthly.filter(monthFilter).first().select('R');
var monthC = C_monthly.filter(monthFilter).first();
var monthP = P_monthly.filter(monthFilter).first();
var monthR_fixed = monthR.unmask(0);
var monthC_fixed = monthC.unmask(0.15);
var monthP_fixed = monthP.unmask(0.35);
var monthModulus = monthR_fixed.multiply(K_250m).multiply(LS_250m)
.multiply(monthC_fixed).multiply(monthP_fixed).rename('Erosion_Modulus');
var monthPixelModulus = monthModulus.divide(areaHectares).rename('Pixel_Erosion_Modulus');
var monthResult = monthModulus.addBands(monthPixelModulus)
.set('month', month).set('period_name', getMonthName(month));
return monthResult;
});
var monthlyModulusCollection = ee.ImageCollection(monthlyErosionModulus);
var annualModulus = monthlyModulusCollection.sum().select('Erosion_Modulus').rename('Annual_Modulus');
var annualPixelModulus = annualModulus.divide(areaHectares).rename('Annual_Pixel_Modulus');
// ================= 4. 可视化设置 =================
// 调整可视化范围以匹配新R因子计算
var modulusVis = {
min: 0, max: 50, // 调整最大值
palette: ['#f7fcf5','#e5f5e0','#c7e9c0','#a1d99b','#74c476','#41ab5d','#238b45','#006d2c','#00441b']
};
var pixelModulusVis = {
min: 0, max: 5, // 调整最大值
palette: ['#f7fbff', '#deebf7', '#c6dbef', '#9ecae1', '#6baed6', '#4292c6', '#2171b5', '#08519c', '#08306b']
};
// R因子可视化调整
var RVis = {
min: 0, max: 2000, // 新公式下的合理范围
palette: ['blue', 'cyan', 'green', 'yellow', 'red']
};
// 侵蚀等级划分调整 - 只显示在区域内
var erosionLevels = annualModulus
.where(annualModulus.lt(5), 1)
.where(annualModulus.gte(5).and(annualModulus.lt(15)), 2)
.where(annualModulus.gte(15).and(annualModulus.lt(30)), 3)
.where(annualModulus.gte(30).and(annualModulus.lt(50)), 4)
.where(annualModulus.gte(50).and(annualModulus.lt(100)), 5)
.where(annualModulus.gte(100), 6)
.rename('Erosion_Level')
.clip(aoi); // 关键修改:只显示在区域内
var levelVis = {
min: 1, max: 6,
palette: ['#d0f0fd','#b2df8a','#ffff99','#fdbf6f','#fb8072','#b2182b']
};
// ================= 5. 完整的界面面板 =================
// 创建主控制面板
var controlPanel = ui.Panel({
style: {
position: 'top-right',
width: '420px', // 增加宽度以容纳更多列
maxHeight: '800px',
stretch: 'vertical'
}
});
// 标题
controlPanel.add(ui.Label('澧水流域土壤侵蚀分析系统 (湘江流域参数)', {
fontWeight: 'bold',
fontSize: '18px',
margin: '0 0 10px 0'
}));
// 年份选择器
var yearSelector = ui.Select({
items: ['2000', '2001', '2002', '2003', '2004', '2005'],
value: '2001',
onChange: function(year) {
print('选择年份: ' + year);
},
style: {width: '100%', margin: '5px 0'}
});
controlPanel.add(ui.Label('选择分析年份:', {margin: '10px 0 5px 0'}));
controlPanel.add(yearSelector);
// 参数信息面板
var paramPanel = ui.Panel({
style: {
padding: '8px',
margin: '8px 0',
border: '1px solid #4CAF50',
backgroundColor: '#f0f9f0'
}
});
paramPanel.add(ui.Label('📊 参数设置说明', {
fontWeight: 'bold',
fontSize: '12px',
margin: '0 0 5px 0',
color: '#2E7D32'
}));
paramPanel.add(ui.Label('R因子范围: 2500-5000', {fontSize: '11px', color: '#555'}));
paramPanel.add(ui.Label('K因子范围: 0.001-0.07', {fontSize: '11px', color: '#555'}));
paramPanel.add(ui.Label('侵蚀模数范围: 0-100 t·hm⁻²·a⁻¹', {fontSize: '11px', color: '#555'}));
controlPanel.add(paramPanel);
// 月度因子统计面板
var monthlyFactorPanel = ui.Panel({
style: {
padding: '10px',
margin: '10px 0',
border: '1px solid #ddd',
backgroundColor: '#fff8f0'
}
});
monthlyFactorPanel.add(ui.Label('月度因子统计', {
fontWeight: 'bold',
fontSize: '14px',
margin: '0 0 8px 0'
}));
// 创建月度因子表格的函数
function createMonthlyFactorTable() {
// 清除现有内容(保留标题)
while (monthlyFactorPanel.widgets().length > 1) {
monthlyFactorPanel.remove(monthlyFactorPanel.widgets().get(1));
}
var loadingLabel = ui.Label('正在计算月度因子数据...', {color: 'gray'});
monthlyFactorPanel.add(loadingLabel);
// 计算每个月的各因子平均值
var monthlyStats = ee.List.sequence(1, 12).map(function(month) {
month = ee.Number(month);
// 获取当月各因子
var monthFilter = ee.Filter.eq('month', month);
var monthR = R_monthly.filter(monthFilter).first().select('R');
var monthC = C_monthly.filter(monthFilter).first();
var monthP = P_monthly.filter(monthFilter).first();
var monthLS = LS; // LS因子不随月份变化
// 计算平均值
var rMean = monthR.reduceRegion({
reducer: ee.Reducer.mean(),
geometry: aoi,
scale: targetScale,
maxPixels: 1e13
}).get('R');
var cMean = monthC.reduceRegion({
reducer: ee.Reducer.mean(),
geometry: aoi,
scale: targetScale,
maxPixels: 1e13
}).get('C');
var pMean = monthP.reduceRegion({
reducer: ee.Reducer.mean(),
geometry: aoi,
scale: targetScale,
maxPixels: 1e13
}).get('P');
var kMean = K.reduceRegion({
reducer: ee.Reducer.mean(),
geometry: aoi,
scale: targetScale,
maxPixels: 1e13
}).get('K');
var lsMean = monthLS.reduceRegion({
reducer: ee.Reducer.mean(),
geometry: aoi,
scale: targetScale,
maxPixels: 1e13
}).get('LS');
// 计算当月侵蚀模数
var monthModulus = monthlyModulusCollection.filter(monthFilter).first();
var modulusMean = monthModulus.reduceRegion({
reducer: ee.Reducer.mean(),
geometry: aoi,
scale: targetScale,
maxPixels: 1e13
}).get('Erosion_Modulus');
return ee.Feature(null, {
'month': month,
'R': ee.Algorithms.If(ee.Algorithms.IsEqual(rMean, null), 0, rMean),
'C': ee.Algorithms.If(ee.Algorithms.IsEqual(cMean, null), 0.2, cMean),
'P': ee.Algorithms.If(ee.Algorithms.IsEqual(pMean, null), 0.4, pMean),
'K': ee.Algorithms.If(ee.Algorithms.IsEqual(kMean, null), 0.045, kMean),
'LS': ee.Algorithms.If(ee.Algorithms.IsEqual(lsMean, null), 1.0, lsMean),
'Modulus': ee.Algorithms.If(ee.Algorithms.IsEqual(modulusMean, null), 0, modulusMean),
'month_name': getMonthName(month)
});
});
var monthlyStatsCollection = ee.FeatureCollection(monthlyStats);
// 异步获取数据
monthlyStatsCollection.evaluate(function(stats) {
monthlyFactorPanel.remove(loadingLabel);
// 创建表格标题
var headerPanel = ui.Panel({
widgets: [
ui.Label('月份', {width: '45px', fontWeight: 'bold', fontSize: '10px'}),
ui.Label('R因子', {width: '50px', fontWeight: 'bold', fontSize: '10px'}),
ui.Label('C因子', {width: '45px', fontWeight: 'bold', fontSize: '10px'}),
ui.Label('P因子', {width: '45px', fontWeight: 'bold', fontSize: '10px'}),
ui.Label('K因子', {width: '45px', fontWeight: 'bold', fontSize: '10px'}),
ui.Label('LS因子', {width: '45px', fontWeight: 'bold', fontSize: '10px'}),
ui.Label('侵蚀模数', {width: '60px', fontWeight: 'bold', fontSize: '10px'})
],
layout: ui.Panel.Layout.Flow('horizontal')
});
monthlyFactorPanel.add(headerPanel);
// 格式化数字函数
function formatNumber(value, decimals) {
if (value === null || value === undefined) return '-';
var num = Number(value);
return num.toFixed(decimals);
}
// 添加每月数据行
stats.features.forEach(function(feature, index) {
var props = feature.properties;
var rowPanel = ui.Panel({
widgets: [
ui.Label(props.month_name, {width: '45px', fontSize: '10px'}),
ui.Label(formatNumber(props.R, 0), {width: '50px', fontSize: '9px', color: '#0066cc'}),
ui.Label(formatNumber(props.C, 3), {width: '45px', fontSize: '9px', color: '#009900'}),
ui.Label(formatNumber(props.P, 3), {width: '45px', fontSize: '9px', color: '#cc6600'}),
ui.Label(formatNumber(props.K, 4), {width: '45px', fontSize: '9px', color: '#8B4513'}),
ui.Label(formatNumber(props.LS, 2), {width: '45px', fontSize: '9px', color: '#FF4500'}),
ui.Label(formatNumber(props.Modulus, 1), {width: '60px', fontSize: '9px', color: '#cc0000', fontWeight: 'bold'})
],
layout: ui.Panel.Layout.Flow('horizontal')
});
monthlyFactorPanel.add(rowPanel);
});
// 添加年度平均值行
var annualR = R.reduceRegion({reducer: ee.Reducer.mean(), geometry: aoi, scale: targetScale, maxPixels: 1e13}).get('R');
var annualC = C.reduceRegion({reducer: ee.Reducer.mean(), geometry: aoi, scale: targetScale, maxPixels: 1e13}).get('C');
var annualP = P.reduceRegion({reducer: ee.Reducer.mean(), geometry: aoi, scale: targetScale, maxPixels: 1e13}).get('P');
var annualK = K.reduceRegion({reducer: ee.Reducer.mean(), geometry: aoi, scale: targetScale, maxPixels: 1e13}).get('K');
var annualLS = LS.reduceRegion({reducer: ee.Reducer.mean(), geometry: aoi, scale: targetScale, maxPixels: 1e13}).get('LS');
var annualModulusMean = annualModulus.reduceRegion({reducer: ee.Reducer.mean(), geometry: aoi, scale: targetScale, maxPixels: 1e13}).get('Annual_Modulus');
// 异步获取年度平均值
annualR.evaluate(function(rVal) {
annualC.evaluate(function(cVal) {
annualP.evaluate(function(pVal) {
annualK.evaluate(function(kVal) {
annualLS.evaluate(function(lsVal) {
annualModulusMean.evaluate(function(mVal) {
var summaryPanel = ui.Panel({
widgets: [
ui.Label('年度平均', {width: '45px', fontSize: '10px', fontWeight: 'bold'}),
ui.Label(formatNumber(rVal, 0), {width: '50px', fontSize: '9px', color: '#0066cc', fontWeight: 'bold'}),
ui.Label(formatNumber(cVal, 3), {width: '45px', fontSize: '9px', color: '#009900', fontWeight: 'bold'}),
ui.Label(formatNumber(pVal, 3), {width: '45px', fontSize: '9px', color: '#cc6600', fontWeight: 'bold'}),
ui.Label(formatNumber(kVal, 4), {width: '45px', fontSize: '9px', color: '#8B4513', fontWeight: 'bold'}),
ui.Label(formatNumber(lsVal, 2), {width: '45px', fontSize: '9px', color: '#FF4500', fontWeight: 'bold'}),
ui.Label(formatNumber(mVal, 1), {width: '60px', fontSize: '9px', color: '#cc0000', fontWeight: 'bold'})
],
layout: ui.Panel.Layout.Flow('horizontal')
});
monthlyFactorPanel.add(ui.Label('')); // 空行分隔
monthlyFactorPanel.add(summaryPanel);
// 添加RUSLE公式说明
var formulaPanel = ui.Panel({
style: {
padding: '8px',
margin: '8px 0',
border: '1px solid #ddd',
backgroundColor: '#f8f8f8'
}
});
formulaPanel.add(ui.Label('📐 RUSLE公式: A = R × K × LS × C × P', {
fontWeight: 'bold',
fontSize: '11px',
margin: '0 0 4px 0'
}));
formulaPanel.add(ui.Label('A: 土壤侵蚀模数 (t·hm⁻²·a⁻¹)', {fontSize: '10px', color: '#555'}));
formulaPanel.add(ui.Label('R: 降雨侵蚀力因子', {fontSize: '10px', color: '#555'}));
formulaPanel.add(ui.Label('K: 土壤可蚀性因子', {fontSize: '10px', color: '#555'}));
formulaPanel.add(ui.Label('LS: 坡长坡度因子', {fontSize: '10px', color: '#555'}));
formulaPanel.add(ui.Label('C: 植被覆盖因子', {fontSize: '10px', color: '#555'}));
formulaPanel.add(ui.Label('P: 水土保持措施因子', {fontSize: '10px', color: '#555'}));
monthlyFactorPanel.add(formulaPanel);
});
});
});
});
});
});
});
}
// 月度因子详细分析按钮
var monthlyFactorButton = ui.Button({
label: '显示月度因子详细数据',
onClick: createMonthlyFactorTable,
style: {margin: '5px 0', width: '100%', backgroundColor: '#ff9800', color: 'white'}
});
monthlyFactorPanel.add(monthlyFactorButton);
controlPanel.add(monthlyFactorPanel);
// 图层控制面板
var layerControlPanel = ui.Panel({
style: {
padding: '10px',
margin: '10px 0',
border: '1px solid #ddd',
backgroundColor: '#f9f9f9'
}
});
layerControlPanel.add(ui.Label('图层控制', {
fontWeight: 'bold',
fontSize: '14px',
margin: '0 0 8px 0'
}));
// 侵蚀模数图层控制
var erosionLayers = [
{name: '年度侵蚀模数', layer: annualModulus, vis: modulusVis},
{name: '像元侵蚀模数', layer: annualPixelModulus, vis: pixelModulusVis},
{name: '侵蚀等级', layer: erosionLevels, vis: levelVis}
];
erosionLayers.forEach(function(layerInfo, index) {
var checkbox = ui.Checkbox({
value: index === 0,
onChange: function(checked) {
if (checked) {
Map.addLayer(layerInfo.layer, layerInfo.vis, layerInfo.name);
} else {
Map.layers().forEach(function(existingLayer, i) {
if (existingLayer.getName() === layerInfo.name) {
Map.remove(existingLayer);
}
});
}
},
style: {margin: '2px 5px'}
});
var label = ui.Label(layerInfo.name, {margin: '2px 5px'});
var row = ui.Panel({
widgets: [checkbox, label],
layout: ui.Panel.Layout.Flow('horizontal')
});
layerControlPanel.add(row);
});
controlPanel.add(layerControlPanel);
// 因子图层控制
var factorControlPanel = ui.Panel({
style: {
padding: '10px',
margin: '10px 0',
border: '1px solid #ddd',
backgroundColor: '#f9f9f9'
}
});
factorControlPanel.add(ui.Label('因子图层', {
fontWeight: 'bold',
fontSize: '14px',
margin: '0 0 8px 0'
}));
var factorLayers = [
{name: 'R因子(降雨侵蚀力)', layer: R, vis: RVis},
{name: 'K因子(土壤可蚀性)', layer: K, vis: {min: 0, max: 0.07, palette: ['white', 'lightbrown', 'brown', 'darkbrown']}},
{name: 'LS因子(地形)', layer: LS, vis: {min: 0, max: 25, palette: ['white', 'lightgreen', 'green', 'yellow', 'orange', 'red']}},
{name: 'C因子(植被覆盖)', layer: C, vis: {min: 0, max: 1, palette: ['darkgreen', 'green', 'yellow', 'red']}},
{name: 'P因子(水土保持)', layer: P, vis: {min: 0, max: 1, palette: ['blue', 'cyan', 'yellow', 'red']}}
];
factorLayers.forEach(function(layerInfo) {
var checkbox = ui.Checkbox({
value: false,
onChange: function(checked) {
if (checked) {
Map.addLayer(layerInfo.layer, layerInfo.vis, layerInfo.name);
} else {
Map.layers().forEach(function(existingLayer, i) {
if (existingLayer.getName() === layerInfo.name) {
Map.remove(existingLayer);
}
});
}
},
style: {margin: '2px 5px'}
});
var label = ui.Label(layerInfo.name, {margin: '2px 5px'});
var row = ui.Panel({
widgets: [checkbox, label],
layout: ui.Panel.Layout.Flow('horizontal')
});
factorControlPanel.add(row);
});
controlPanel.add(factorControlPanel);
// 统计信息面板
var statsPanel = ui.Panel({
style: {
padding: '12px',
margin: '10px 0',
border: '1px solid #ccc',
backgroundColor: '#fff'
}
});
statsPanel.add(ui.Label('年度统计结果', {
fontWeight: 'bold',
fontSize: '16px',
margin: '0 0 10px 0'
}));
// 更新统计信息的函数
function updateStatistics() {
// 更新年度统计
updateAnnualStatistics();
// 更新月度因子表格
createMonthlyFactorTable();
}
function updateAnnualStatistics() {
// 清除现有统计内容(保留标题)
while (statsPanel.widgets().length > 1) {
statsPanel.remove(statsPanel.widgets().get(1));
}
// 添加加载提示
var loadingLabel = ui.Label('正在计算统计信息...', {color: 'gray'});
statsPanel.add(loadingLabel);
// 侵蚀模数统计
var erosionStats = annualModulus.reduceRegion({
reducer: ee.Reducer.mean()
.combine(ee.Reducer.min(), null, true)
.combine(ee.Reducer.max(), null, true)
.combine(ee.Reducer.median(), null, true),
geometry: aoi,
scale: targetScale,
maxPixels: 1e13
});
// 各因子统计
var factorMeans = {
R: R.reduceRegion({reducer: ee.Reducer.mean(), geometry: aoi, scale: targetScale, maxPixels: 1e13}).get('R'),
K: K.reduceRegion({reducer: ee.Reducer.mean(), geometry: aoi, scale: targetScale, maxPixels: 1e13}).get('K'),
LS: LS.reduceRegion({reducer: ee.Reducer.mean(), geometry: aoi, scale: targetScale, maxPixels: 1e13}).get('LS'),
C: C.reduceRegion({reducer: ee.Reducer.mean(), geometry: aoi, scale: targetScale, maxPixels: 1e13}).get('C'),
P: P.reduceRegion({reducer: ee.Reducer.mean(), geometry: aoi, scale: targetScale, maxPixels: 1e13}).get('P')
};
// 使用evaluate异步获取结果
erosionStats.evaluate(function(erosionResult) {
factorMeans.R.evaluate(function(rMean) {
factorMeans.K.evaluate(function(kMean) {
factorMeans.LS.evaluate(function(lsMean) {
factorMeans.C.evaluate(function(cMean) {
factorMeans.P.evaluate(function(pMean) {
// 移除加载提示
statsPanel.remove(loadingLabel);
function formatNumber(value, decimals) {
if (value === null || value === undefined) return 'N/A';
return Number(value).toFixed(decimals);
}
// 添加侵蚀模数统计
statsPanel.add(ui.Label('📊 侵蚀模数统计:', {fontWeight: 'bold', margin: '8px 0 4px 0'}));
statsPanel.add(ui.Label(' 平均值: ' + formatNumber(erosionResult.Annual_Modulus_mean, 1) + ' t·hm⁻²·a⁻¹'));
statsPanel.add(ui.Label(' 最小值: ' + formatNumber(erosionResult.Annual_Modulus_min, 1) + ' t·hm⁻²·a⁻¹'));
statsPanel.add(ui.Label(' 最大值: ' + formatNumber(erosionResult.Annual_Modulus_max, 1) + ' t·hm⁻²·a⁻¹'));
statsPanel.add(ui.Label(' 中位数: ' + formatNumber(erosionResult.Annual_Modulus_median, 1) + ' t·hm⁻²·a⁻¹'));
// 添加各因子统计
statsPanel.add(ui.Label('🔬 各因子年度平均值:', {fontWeight: 'bold', margin: '8px 0 4px 0'}));
statsPanel.add(ui.Label(' R: ' + formatNumber(rMean, 0)));
statsPanel.add(ui.Label(' K: ' + formatNumber(kMean, 4)));
statsPanel.add(ui.Label(' LS: ' + formatNumber(lsMean, 2)));
statsPanel.add(ui.Label(' C: ' + formatNumber(cMean, 3)));
statsPanel.add(ui.Label(' P: ' + formatNumber(pMean, 3)));
});
});
});
});
});
});
}
// 添加更新统计按钮
var updateButton = ui.Button({
label: '更新所有统计信息',
onClick: updateStatistics,
style: {margin: '10px 0', width: '100%'}
});
controlPanel.add(updateButton);
controlPanel.add(statsPanel);
// 时间序列图表面板
var chartPanel = ui.Panel({
style: {
padding: '10px',
margin: '10px 0',
border: '1px solid #ddd'
}
});
chartPanel.add(ui.Label('时间序列分析', {
fontWeight: 'bold',
fontSize: '14px',
margin: '0 0 8px 0'
}));
// 月度侵蚀模数图表数据准备
var monthlyModulusStats = ee.List.sequence(1, 12).map(function(month) {
month = ee.Number(month);
var monthFilter = ee.Filter.eq('month', month);
var monthImage = monthlyModulusCollection.filter(monthFilter).first();
var monthMeanModulus = monthImage.reduceRegion({
reducer: ee.Reducer.mean(),
geometry: aoi,
scale: targetScale,
maxPixels: 1e13
}).get('Erosion_Modulus');
monthMeanModulus = ee.Algorithms.If(
ee.Algorithms.IsEqual(monthMeanModulus, null),
0,
monthMeanModulus
);
return ee.Feature(null, {
'month': month,
'modulus': ee.Number(monthMeanModulus),
'month_name': getMonthName(month)
});
});
// 创建图表
var chartFeatures = ee.FeatureCollection(monthlyModulusStats);
var modulusChart = ui.Chart.feature.byFeature({
features: chartFeatures,
xProperty: 'month',
yProperties: ['modulus']
}).setOptions({
title: analysisYear + '年澧水流域月度土壤侵蚀模数',
hAxis: {title: '月份', gridlines: {count: 12}},
vAxis: {title: '侵蚀模数 (t·hm⁻²·月⁻¹)'},
lineWidth: 3,
pointSize: 5,
series: {0: {color: '#238b45'}},
height: 200,
chartArea: {width: '85%', height: '70%'}
});
// 将图表添加到面板
chartPanel.add(modulusChart);
controlPanel.add(chartPanel);
// 导出控制面板
var exportPanel = ui.Panel({
style: {
padding: '10px',
margin: '10px 0',
border: '1px solid #ddd',
backgroundColor: '#f0f8ff'
}
});
exportPanel.add(ui.Label('数据导出', {
fontWeight: 'bold',
fontSize: '14px',
margin: '0 0 8px 0'
}));
var exportButton = ui.Button({
label: '导出所有结果到Google Drive',
onClick: function() {
exportAllData();
var exportLabel = ui.Label({
value: '✅ 导出任务已启动,请在Tasks面板查看进度',
style: {color: 'green', margin: '10px', backgroundColor: '#f0fff0', padding: '5px'}
});
controlPanel.add(exportLabel);
setTimeout(function() {
controlPanel.remove(exportLabel);
}, 3000);
},
style: {margin: '5px 0', width: '100%', backgroundColor: '#4CAF50', color: 'white'}
});
exportPanel.add(exportButton);
controlPanel.add(exportPanel);
// 添加到地图
Map.add(controlPanel);
// 初始化时更新统计信息
updateStatistics();
// ================= 6. 导出函数 =================
function exportAllData() {
Export.image.toDrive({
image: annualModulus,
description: 'Lishui_Annual_Erosion_Modulus_' + analysisYear,
folder: modulusFolder,
scale: targetScale,
region: aoi,
maxPixels: 1e13,
fileFormat: 'GeoTIFF'
});
Export.image.toDrive({
image: annualPixelModulus,
description: 'Lishui_Annual_Pixel_Erosion_Modulus_' + analysisYear,
folder: modulusFolder,
scale: targetScale,
region: aoi,
maxPixels: 1e13,
fileFormat: 'GeoTIFF'
});
Export.image.toDrive({
image: erosionLevels,
description: 'Lishui_Erosion_Levels_' + analysisYear,
folder: modulusFolder,
scale: targetScale,
region: aoi,
maxPixels: 1e13,
fileFormat: 'GeoTIFF'
});
for (var i = 0; i < 12; i++) {
var month = i + 1;
var monthImg = monthlyModulusCollection.filter(ee.Filter.eq('month', month)).first();
var monthCode = 'LS' + analysisYear + '_Month_' + month;
Export.image.toDrive({
image: monthImg.select('Pixel_Erosion_Modulus'),
description: monthCode,
folder: exportRootFolder,
scale: targetScale,
region: aoi,
maxPixels: 1e13,
fileFormat: 'GeoTIFF'
});
}
var factors = {'R': R, 'K': K, 'LS': LS, 'C': C, 'P': P};
for (var factorName in factors) {
Export.image.toDrive({
image: factors[factorName],
description: 'Lishui_' + factorName + '_Factor_' + analysisYear,
folder: factorFolder,
scale: targetScale,
region: aoi,
maxPixels: 1e13,
fileFormat: 'GeoTIFF'
});
}
print('✅ 所有导出任务已提交到Tasks面板');
}
// ================= 7. 图例和初始化 =================
// 侵蚀等级图例
var erosionLegend = ui.Panel({
style: {
position: 'bottom-right',
padding: '8px 15px',
backgroundColor: 'white',
border: '1px solid #ccc'
}
});
erosionLegend.add(ui.Label('土壤侵蚀等级 (t·hm⁻²·a⁻¹)', {
fontWeight: 'bold', fontSize: '14px', margin: '0 0 6px 0'
}));
var levelNames = ['1: 微度侵蚀 (<5)', '2: 轻度侵蚀 (5-15)', '3: 中度侵蚀 (15-30)',
'4: 强度侵蚀 (30-50)', '5: 极强度侵蚀 (50-100)', '6: 剧烈侵蚀 (>100)'];
var levelColors = ['#d0f0fd', '#b2df8a', '#ffff99', '#fdbf6f', '#fb8072', '#b2182b'];
for (var i = 0; i < 6; i++) {
var colorBox = ui.Label({style: {backgroundColor: levelColors[i], padding: '8px', margin: '0 0 4px 0', width: '20px'}});
var description = ui.Label({value: levelNames[i], style: {margin: '0 0 4px 8px', fontSize: '12px'}});
var legendItem = ui.Panel({widgets: [colorBox, description], layout: ui.Panel.Layout.Flow('horizontal')});
erosionLegend.add(legendItem);
}
Map.add(erosionLegend);
// 系统信息面板 - 更新R因子信息
var infoPanel = ui.Panel({
style: {
position: 'bottom-left',
padding: '10px',
margin: '10px',
backgroundColor: 'rgba(255,255,255,0.9)',
border: '1px solid #ccc',
maxWidth: '300px'
}
});
infoPanel.add(ui.Label('系统信息', {fontWeight: 'bold', fontSize: '14px', margin: '0 0 8px 0'}));
infoPanel.add(ui.Label('🗓️ 分析年份: ' + analysisYear));
infoPanel.add(ui.Label('📐 空间分辨率: ' + targetScale + 'm'));
infoPanel.add(ui.Label('📊 R因子公式: R = -8.12 + 0.562 × 降雨量'));
infoPanel.add(ui.Label('🏔️ 流域特征: 山区地形复杂'));
infoPanel.add(ui.Label('🌱 主要植被: 森林、农田'));
infoPanel.add(ui.Label('🔍 侵蚀等级: 仅显示区域内'));
Map.add(infoPanel);
// 初始化显示
Map.addLayer(annualModulus, modulusVis, '年度侵蚀模数');
Map.addLayer(erosionLevels, levelVis, '侵蚀等级');
print('🎉 澧水流域土壤侵蚀分析系统已启动!(新R因子公式)');
print('📍 R因子使用新公式: R = -8.12 + 0.562 × 降雨量');
print('📊 侵蚀等级图层现在只显示在澧水流域区域内');
print('💾 点击导出按钮保存结果');
print('📈 点击"显示月度因子详细数据"查看每月各因子数值');对2000-2020年的数据进行mk检验并出图
最新发布