今天的内容是复制本人自己的实验报告,放心食用。最后放全部代码!如果不想看前面的东西就直接拉到后面!前面的代码懒得一个一个插代码段了,要复制的拉到最后去复制。本篇涵盖了之前写的好几篇博客的内容。
计算粤港澳城市群2005,2015,和2022三年的城市热岛强度。
使用的数据为MODIS_061_MYD11A2,即Aqua拍摄的地表温度数据,过境时间约为下午1:30和凌晨1:30。
在上一次不透水面提取的实验基础上,基于不透水面的斑块,计算这个斑块范围内的MNDWI(如图1),设置阈值为0,筛选出MNDWI<0的区域。代码如下,其中的and运算就做了一个不透水面和非水体的区域取交集的运算。
图 1 MNDWI计算结果
转矢量使用的是reduceToVectors函数,同时给转好的矢量添加面积字段。因为转之后的向量一般有好几个,其中只有一个是最大的,基本涵盖了原始image的全部范围。所以之后根据面积筛选最大的斑块。因为大部分代码和上一次实验相同,就不展示了,最后是哟女export函数导出结果,命名为city,这个collection是3年的城市矢量,一年一个。详见我写的博客:http://t.csdn.cn/MeoJY。
计算UHI需要剔除高程的影响。下面的代码只需要运行一次,就可以得到研究区域的DEM的均值。筛选出研究区域内高程在均值±100m范围内的部分。具体的reduceRegion求均值的解释可以看我的这一篇博客:http://t.csdn.cn/BwqqJ。
下面的lt()函数内部就是每一年研究区域均值+100m的结果,因为研究区域没有高程-100m的地方,所以就不做下限的约束。
这里直接选取了5km作为缓冲区半径,往外做5km的缓冲区。得到了乡村和城市的区域之和。为了得到纯乡村,用缓冲区.difference(城市)就可以得到去掉了城市区域的缓冲区,即乡村。同理,对乡村也做高程的约束。
现在开始使用MODIS的LST数据,计算城市和乡村的一段时间序列中的日夜平均温度。这一大节“2.制作时间序列影像集”具体解释可以看我写的这一篇博客:http://t.csdn.cn/71SdO。5年总共有138景影像。
图 2 得到一定时间序列的影像集
MODIS的LST数据的温度是开尔文温度,需要转成摄氏度。代码里面的false_temperature 代指开尔文温度,而tru_temperature代指摄氏度。计算公式是:真实的地表温度 = MODIS中的地表温度*0.02-273.15;之后我们把每一天的早晚温度算出来,加在属性中。
对于数据需要做一下质量控制,筛选出受云的影响较小,且成像质量高的影像。下面的函数可以提取指定位置qc二进制码。
注意这个函数只能接受QC波段为int类型,不可为double,如果前面从imagecollection筛选影像的时候用到了median或者mean,就会把影像的全部波段都变成double类型,包括QC波段。因此,前面为了将imagecollection中唯一的那一个影像转成image,要使用max或者min。
然后将城市和乡村的时间序列影像集都过一遍这个函数,得到QC波段指定比特位置的数字。根据MODIS_GEE的指南,我们需要提取下面的代码仅展示城市影像集的,乡村的同理。
图 3 GEE关于MODIS数据各波段的说明
图 4 QC_DAY波段的每一个bit的含义说明
// calculate the quality of each image
var qc_account_city = tru_city.map(function(img){
var img_temp = ee.Image(img)
var date = img_temp.get('system:time_start');
var year = ee.Date(date).get( 'year' );
var city_poly=ee.Algorithms.If(ee.Number(year).eq(2005),city1,(ee.Algorithms.If(ee.Number(year).eq(2015),city2,city3))); // city
var poly_area = ee.Feature(city_poly).get('area');
var newband = ee.Image.constant(1)
img_temp = img_temp.addBands(newband)
var area_image = img_temp.multiply(ee.Image.pixelArea())
var qcDay = img.select('QC_Day');
var qcNight = img.select('QC_Night');
var qadayMask = bitwiseExtract(qcDay, 0, 1).lte(1)
var dataQualityMask1 = bitwiseExtract(qcDay, 2, 3).eq(0)
var qanightMask = bitwiseExtract(qcNight, 0, 1).lte(1)
var dataQualityMask2 = bitwiseExtract(qcNight, 2, 3).eq(0)
var mask1 = qadayMask.and(dataQualityMask1)
var mask2 = qanightMask.and(dataQualityMask2)
var area1 = area_image.updateMask(mask1).reduceRegion({
reducer: ee.Reducer.sum(),
geometry: ee.Feature(city_poly).geometry(),
scale: 1000,
maxPixels: 10e15,
});
//convert sqkm //面积比例
var area_sqkm1 = ee.Number(area1.get('constant')).divide(1e6)
var day_account = area_sqkm1.divide(poly_area).multiply(100).round();
var area2 = area_image.updateMask(mask2).reduceRegion({
reducer: ee.Reducer.sum(),
geometry: ee.Feature(city_poly).geometry(),
scale: 1000,
maxPixels: 10e15,
});
//convert sqkm //面积比例
var area_sqkm2 = ee.Number(area2.get('constant')).divide(1e6)
var night_account = area_sqkm2.divide(poly_area).multiply(100).round();
return img_temp.set('day_account',day_account).set('night_account',night_account);
})
将城市和乡村的每期影像的平均温度求出后,需要匹配同一拍摄时间的城市和乡村的影像。这里用到了join,它有点像是数据库的操作,没有改变原始数据,而是生成了一个新的collection,将两个数据关联了起来,这里是直接把两个数据同等级地存在了一起,用的函数是ee.Join.inner,如果用其他的函数join出来的结果是有包含关系的。
这里用的是ui.Chart.feature.byFeature来做图,参数分别为需要作图的数据,横坐标数据(属性名),纵坐标数据(属性名)。制作的是直方图。
效果如下图所示:
综合三年的结果,如下图所示:可以看出,白天的城市热岛强度普遍低于夜间。
季节方面。虽然夏季的高质量影响较少,但可以看出白天城市热岛强度在夏季最强,从八月份之后逐渐减弱,八月后的热岛强度有非常线性的关系。2005和2015年春夏季的热岛强度随季节无明显变化,而2022年城市热岛强度随月份的递增有明显的上升趋势。而夜间热岛强度无规则的月度和季度变化。
图 5 三年白天和晚上的城市热岛强度,(a)(b)为2005年,(c)(d)为2015年,(e)(f)为2022年
年际变化。从整体趋势来看,热岛强度逐年递增,且增速较为平稳。2015年有三年中的最大值和最小值,离散程度也最大,也是唯一的白天出现负的热岛强度的一年。
夜间热岛强度的平均值随着年份的递增呈波动趋势,但中位数和最大值略有上升。最小值依然出现在2015年,但最大值出现在了2022年。离散程度最大的目测仍是2015年。
【代码大放送!下面代码很长,谨慎点开】
// load the study area
var roi = ee.FeatureCollection(table);
Map.addLayer(roi, {}, 'roi',false);
Map.centerObject(roi,8);//Feature with MultiPolygon
var dem_city = DEM.select('elevation')
// //--------------------------- calculate the mean dem (Just run once!) ----------
// var means = roi.map(function(roi){
// var rural_city = roi.buffer(5000,1000);
// var meanDict = dem_city.reduceRegion({
// reducer: ee.Reducer.mean(),
// geometry:rural_city.geometry(),
// scale: 1000,
// maxPixels: 1e9
// });
// var dem_mean = ee.Image.constant(meanDict.values());
// // find the region where elev is larger than the mean value of the total study area
// return dem_mean // 2005:mean:21.54,2015:20.85,2022:21.53
// })
// -------------------------get each year's 【city】 region(feature)--------------------------
var city1=roi.filter(ee.Filter.eq('ID',1)).first(); //
var city2=roi.filter(ee.Filter.eq('ID',2)).first();
var city3=roi.filter(ee.Filter.eq('ID',3)).first();
// find the city region with dem < 100+mean;
var city_less1 = dem_city.lt(121.54).clip(city1) //image,"elevation", int ∈ [0, 1]
var city_less2 = dem_city.lt(120.84).clip(city2)
var city_less3 = dem_city.lt(121.53).clip(city3)
var citys = ee.ImageCollection([city_less1,city_less2,city_less3])
// -------------------------get each year's 【rural+city】 region--------------------------
var rural_citys = roi.map(function(roi){
var rural_city = roi.buffer(5000,1000);
return rural_city// Feature, with 8 properties
})
// -------------------------get each year's 【rural】 region--------------------------
var rural1=ee.Feature(rural_citys.filter(ee.Filter.eq('ID',1)).first()).difference(city1);
var rural2=ee.Feature(rural_citys.filter(ee.Filter.eq('ID',2)).first()).difference(city2);
var rural3=ee.Feature(rural_citys.filter(ee.Filter.eq('ID',3)).first()).difference(city3);
// -------------------------get each year's 【rural(demImage (3 bands)
// ---------Control the quality and Convert temperature to Celsius.-------------------
var convert = function(img){
var img = ee.Image(img)
var date = img.get('system:time_start');
//control the quality
var lstDay = img.select('LST_Day_1km');
var lstNight = img.select('LST_Night_1km');
var qcDay = img.select('QC_Day');
var qcNight = img.select('QC_Night');
// ---------calculate the Celsius------------------------------------------
var day_wendu = lstDay.multiply(0.02).subtract(273.15);
var night_wendu = lstNight.multiply(0.02).subtract(273.15);
var final = qcDay.addBands(day_wendu).addBands(night_wendu).addBands(qcNight).set('system:time_start',date);
return final;
};
var tru_city = false_temperature_city.map(convert);//ImageCollection (129 elements)->Image (4 bands),5 properties
var tru_rural = false_temperature_rural.map(convert);
// print('tru_city',tru_city)
// Map.addLayer(ee.Feature(city1))
// calculate the quality of each image
var qc_account_city = tru_city.map(function(img){
var img_temp = ee.Image(img)
var date = img_temp.get('system:time_start');
var year = ee.Date(date).get( 'year' );
var city_poly=ee.Algorithms.If(ee.Number(year).eq(2005),city1,(ee.Algorithms.If(ee.Number(year).eq(2015),city2,city3))); // city
var poly_area = ee.Feature(city_poly).get('area');
var newband = ee.Image.constant(1)
img_temp = img_temp.addBands(newband)
var area_image = img_temp.multiply(ee.Image.pixelArea())
var qcDay = img.select('QC_Day');
var qcNight = img.select('QC_Night');
var qadayMask = bitwiseExtract(qcDay, 0, 1).lte(1)
var dataQualityMask1 = bitwiseExtract(qcDay, 2, 3).eq(0)
var qanightMask = bitwiseExtract(qcNight, 0, 1).lte(1)
var dataQualityMask2 = bitwiseExtract(qcNight, 2, 3).eq(0)
var mask1 = qadayMask.and(dataQualityMask1)
var mask2 = qanightMask.and(dataQualityMask2)
var area1 = area_image.updateMask(mask1).reduceRegion({
reducer: ee.Reducer.sum(),
geometry: ee.Feature(city_poly).geometry(),
scale: 1000,
maxPixels: 10e15,
});
//convert sqkm //面积比例
var area_sqkm1 = ee.Number(area1.get('constant')).divide(1e6)
var day_account = area_sqkm1.divide(poly_area).multiply(100).round();
var area2 = area_image.updateMask(mask2).reduceRegion({
reducer: ee.Reducer.sum(),
geometry: ee.Feature(city_poly).geometry(),
scale: 1000,
maxPixels: 10e15,
});
//convert sqkm //面积比例
var area_sqkm2 = ee.Number(area2.get('constant')).divide(1e6)
var night_account = area_sqkm2.divide(poly_area).multiply(100).round();
return img_temp.set('day_account',day_account).set('night_account',night_account);
})
var qc_account_rural = tru_rural.map(function(img){
var img_temp = ee.Image(img)
var date = img_temp.get('system:time_start');
var year = ee.Date(date).get( 'year' );
var rural_poly=ee.Algorithms.If(ee.Number(year).eq(2005),rural1,(ee.Algorithms.If(ee.Number(year).eq(2015),rural2,rural3))); // rural
var poly_area = ee.Feature(rural_poly).get('area');
var newband = ee.Image.constant(1)
img_temp = img_temp.addBands(newband)
var area_image = img_temp.multiply(ee.Image.pixelArea())
var qcDay = img.select('QC_Day');
var qcNight = img.select('QC_Night');
var qadayMask = bitwiseExtract(qcDay, 0, 1).lte(1)
var dataQualityMask1 = bitwiseExtract(qcDay, 2, 3).eq(0)
var qanightMask = bitwiseExtract(qcNight, 0, 1).lte(1)
var dataQualityMask2 = bitwiseExtract(qcNight, 2, 3).eq(0)
var mask1 = qadayMask.and(dataQualityMask1)
var mask2 = qanightMask.and(dataQualityMask2)
var area1 = area_image.updateMask(mask1).reduceRegion({
reducer: ee.Reducer.sum(),
geometry: ee.Feature(rural_poly).geometry(),
scale: 1000,
maxPixels: 10e15,
});
var area_sqkm1 = ee.Number(area1.get('constant')).divide(1e6)
var day_account = area_sqkm1.divide(poly_area).multiply(100).round();
var area2 = area_image.updateMask(mask2).reduceRegion({
reducer: ee.Reducer.sum(),
geometry: ee.Feature(rural_poly).geometry(),
scale: 1000,
maxPixels: 10e15,
});
var area_sqkm2 = ee.Number(area2.get('constant')).divide(1e6)
var night_account = area_sqkm2.divide(poly_area).multiply(100).round();
return img_temp.set('day_account',day_account).set('night_account',night_account);
})
var qc_tru_city = qc_account_city.filter(ee.Filter.gt('day_account',10)).filter(ee.Filter.gt('night_account',10));
var qc_tru_rural = qc_account_rural.filterMetadata('day_account','greater_than',10).filterMetadata('night_account','greater_than',10);
// print('qc_tru_city',qc_tru_city)
// print('qc_tru_rural',qc_tru_rural)
var city_means_wendu = qc_tru_city.map(function(img){
var day = img.get('system:time_start');
var year = ee.Date(day).get( 'year' );
var city_poly=ee.Algorithms.If(ee.Number(year).eq(2005),city1,(ee.Algorithms.If(ee.Number(year).eq(2015),city2,city3))); // city
var meanDict = img.reduceRegion({
reducer: ee.Reducer.mean(),
geometry:ee.Feature(city_poly).geometry(),
scale: 1000,
maxPixels: 1e9
});
var mean_day = meanDict.values().get(0);
var mean_night = meanDict.values().get(1);
var mean = img.set('mean_day',mean_day).set('mean_night',mean_night);
// var mean = img.set('mean_day',meanDict.values());
return mean
})
// print(city_means_wendu)
var rural_means_wendu = qc_tru_rural.map(function(img){
var day = img.get('system:time_start');
var year = ee.Date(day).get( 'year' );
var rural_poly=ee.Algorithms.If(ee.Number(year).eq(2005),rural1,(ee.Algorithms.If(ee.Number(year).eq(2015),rural2,rural3))); // city
var meanDict = img.reduceRegion({
reducer: ee.Reducer.mean(),
geometry:ee.Feature(rural_poly).geometry(),
scale: 1000,
maxPixels: 1e9
});
var mean_day = meanDict.values().get(0);
var mean_night = meanDict.values().get(1);
var mean = img.set('mean_day',mean_day).set('mean_night',mean_night);
return mean
})
// Map.addLayer(city_means_wendu.first().select('LST_Day_1km'), {min: 10, max: 30, palette: ['green','yellow', 'red']},'city_Day');
// Map.addLayer(city_means_wendu.first().select('LST_Night_1km'), {min: 10, max: 30, palette: ['green','yellow', 'red']},'city_Night');
// Map.addLayer(rural_means_wendu.first().select('LST_Day_1km'), {min: 10, max: 30, palette: ['green','yellow', 'red']},'rural_Day');
// Map.addLayer(rural_means_wendu.first().select('LST_Night_1km'), {min: 10, max: 30, palette: ['green','yellow', 'red']},'rural_Night');
// print('city_means_wendu',city_means_wendu)
// print('rural_means_wendu',rural_means_wendu)
//----------------- join the city and the rural imagecollection-----------------------------
var join_filter = ee.Filter.equals({
// difference: One_Day_Millis,
leftField: 'system:time_start',
rightField: 'system:time_start'
})
var Inner_Join = ee.Join.inner('primary', 'secondary');// 定义一个invertJoin
var Inner_Join_Results = Inner_Join.apply(city_means_wendu, rural_means_wendu, join_filter);// 应用invertJoin
// print('Inner_Join_Results: ', Inner_Join_Results);
var joined = Inner_Join_Results.map(function(feature) {
var city = feature.get('primary');
var rural = feature.get('secondary');
var city_wendu_day = ee.Feature(city).get('mean_day');
var city_wendu_night = ee.Feature(city).get('mean_night');
var rural_wendu_day = ee.Feature(rural).get('mean_day');
var rural_wendu_night = ee.Feature(rural).get('mean_night');
var uhiday = ee.Number(city_wendu_day).subtract(ee.Number(rural_wendu_day));
var uhinight = ee.Number(city_wendu_night).subtract(ee.Number(rural_wendu_night));
var final = ee.Image.cat(feature.get('primary'), feature.get('secondary'))
.set('uhiday',uhiday).set('uhinight',uhinight);
return final
})
// print(joined)
// ------------------------------------------------------出图 -------------------------------------------
var data = ee.FeatureCollection(joined.map(function(img) {
var day = img.get('system:time_start');
var year = ee.Date(day).get( 'year' );
return ee.Feature(null,{time:day,UHI_day:img.get('uhiday'),UHI_night:img.get('uhinight'),year:year})
}));
var chart_day = ui.Chart.feature.byFeature(data.sort('time').filterMetadata('year','equals',2005),'time','UHI_day')
.setChartType('ColumnChart')
.setOptions({
title: '白天城市热岛强度',
hAxis: {title: 'Date'},
vAxis: {title: 'UHI'}
});
var chart_night = ui.Chart.feature.byFeature(data.sort('time').filterMetadata('year','equals',2005),'time','UHI_night')
.setChartType('ColumnChart')
.setOptions({
title: '夜间城市热岛强度',
hAxis: {title: 'Date'},
vAxis: {title: 'UHI'}
});
print(chart_day);
print(chart_night);