Google earth engine(GEE):基于MODIS的LST(地表温度数据)计算一定时间序列的城市热岛强度(UHI),并绘制直方图

2023.01.06更新:

        完整流程是这样的,首先第一个代码可以得到城市斑块,第二个代码可以计算这个地区的城市热岛效应强度.有朋友私信问全部的代码,同时自己也修改了一下计算城市热岛强度代码的一些比较繁琐的地方,搬出最新的代码(原回答的代码没有问题!只是我优化了一下):

        第一个代码(代码很长,谨慎点开):

var first_year = 2003;
var second_year =2007;
var third_year =2013;
var fourth_year = 2018;
var fifth_year =2022;
//---------------------------Part 2 load study area and data-------------------------------------------------------
//load the study area
var roi = ee.Feature(table.filter(ee.Filter.eq('name',11)).first());
Map.addLayer(roi, {}, 'roi');
Map.centerObject(roi,9);

// Applies scaling factors landsat 5.
function applyScaleFactors5(image) {
  var opticalBands = image.select('SR_B.').multiply(0.0000275).add(-0.2);
  var thermalBand = image.select('ST_B6').multiply(0.00341802).add(149.0);
  return image.addBands(opticalBands, null, true)
              .addBands(thermalBand, null, true);
}

// Applies scaling factors for landsat 8.
function applyScaleFactors8(image) {
  var opticalBands = image.select('SR_B.').multiply(0.0000275).add(-0.2);
  var thermalBands = image.select('ST_B.*').multiply(0.00341802).add(149.0);
  return image.addBands(opticalBands, null, true)
              .addBands(thermalBands, null, true);
}

var landsat1 = ee.ImageCollection('LANDSAT/LT05/C02/T1_L2')
    .filterBounds(roi.geometry())
    .filterDate('2003-01-01', '2003-12-01')
    .map(applyScaleFactors5)
    .filter(ee.Filter.lt('CLOUD_COVER',10))
    .median();

var landsat2 = ee.ImageCollection('LANDSAT/LT05/C02/T1_L2')
    .filterBounds(roi.geometry())
    .filterDate('2007-04-11', '2007-04-13')
    .map(applyScaleFactors5)
    .sort('CLOUD_COVER')
    .filter(ee.Filter.lt('CLOUD_COVER',12))
    .median();
                
var landsat3 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')
    .filterBounds(roi.geometry())
    .filterDate('2013-01-01', '2013-12-31')
    .map(applyScaleFactors8)
    .sort('CLOUD_COVER')
    .filter(ee.Filter.lt('CLOUD_COVER',10))
    .median();
                  
var landsat4 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')
    .filterBounds(roi.geometry())
    .filterDate('2018-01-01', '2018-12-31')
    .map(applyScaleFactors8)
    .sort('CLOUD_COVER')
    .filter(ee.Filter.lt('CLOUD_COVER',10))
    .median();

var landsat5 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')
    .filterBounds(roi.geometry())
    .filterDate('2022-01-01', '2022-12-31')
    .map(applyScaleFactors8)
    .filter(ee.Filter.lt('CLOUD_COVER',10))
    .median();
    
// // // print(landsat1);
// print(landsat2);
// print(landsat3);
// print(landsat4);
// // // print(landsat5);

// ----------------------------Calculate the ndvi------------------------
// calculate ndvi
var ndvi1 = landsat1.normalizedDifference(['SR_B4','SR_B3']);
var ndvi2 = landsat2.normalizedDifference(['SR_B4','SR_B3']);
var ndvi3 = landsat3.normalizedDifference(['SR_B5','SR_B4']);
var ndvi4 = landsat4.normalizedDifference(['SR_B5','SR_B4']);
var ndvi5 = landsat5.normalizedDifference(['SR_B5','SR_B4']);
var ndvi_collect = ee.ImageCollection([ndvi1,ndvi2,ndvi3,ndvi4,ndvi5])
var ndvi_mean = ndvi_collect.map(function(img){
  var meanDict = img.reduceRegion({
    reducer: ee.Reducer.mean(),
    geometry:roi.geometry(), 
    scale: 30,
    maxPixels: 1e9
  });
  var mean = meanDict.values().get(0);
  return img.set({ndvi: mean})
})
print(ndvi_mean)
// print(ndvi_mean.toList(5))
var data = ee.FeatureCollection(ndvi_mean.map(function(img) {  
  var ndvi = img.get('ndvi');
  var id = img.get('system:index');
  return ee.Feature(null,{ndvi:ndvi,id:id})  
})); 
// print(data)

Export.table.toDrive({
  collection: data,
  description: 'xianggang_ndvi',
  fileFormat: 'CSV'
});

//---------------------------Part 3 detect urban renewal-------------------------------------------------------
//calculate ndbi
var ndbi1 = landsat1.normalizedDifference(['SR_B5','SR_B4']);
var ndbi2 = landsat2.normalizedDifference(['SR_B5','SR_B4']);
var ndbi3 = landsat3.normalizedDifference(['SR_B6','SR_B5']);
var ndbi4 = landsat4.normalizedDifference(['SR_B6','SR_B5']);
var ndbi5 = landsat5.normalizedDifference(['SR_B6','SR_B5']);

// calculate mndwi
var mndwi1 = landsat1.normalizedDifference(['SR_B2','SR_B5']);
var mndwi2 = landsat2.normalizedDifference(['SR_B2','SR_B5']);
var mndwi3 = landsat3.normalizedDifference(['SR_B3','SR_B6']);
var mndwi4 = landsat4.normalizedDifference(['SR_B3','SR_B6']);
var mndwi5 = landsat5.normalizedDifference(['SR_B3','SR_B6']);

//set thresholds
var mndwi_t = 0;
var ndbi_t = -0.15;

//set thresold for built by NDBI
var built5 = ndbi5.gt(ndbi_t).clip(roi);
built5 = built5.mask(built5);

var built1 = ndbi1.gt(ndbi_t).mask(built5);
var built2 = ndbi2.gt(ndbi_t).mask(built5).or(built1);
var built3 = ndbi3.gt(ndbi_t).mask(built5).or(built2);
var built4 = ndbi4.gt(ndbi_t).mask(built5).or(built3);
built5 = built5.or(built4);

// var collection = ee.ImageCollection([built1,built2,built3,built4,built5])

// set thresold for built by MNDWI
var notwater5 = mndwi5.lt(mndwi_t).clip(roi);
notwater5=notwater5.mask(notwater5);
var notwater4 = mndwi4.lt(mndwi_t).clip(roi);
notwater4=notwater4.mask(notwater4);
var notwater3 = mndwi3.lt(mndwi_t).clip(roi);
notwater3=notwater3.mask(notwater3);
var notwater2 = mndwi2.lt(mndwi_t).clip(roi);
notwater2=notwater2.mask(notwater2);
var notwater1 = mndwi1.lt(mndwi_t).clip(roi);
notwater1=notwater1.mask(notwater1);

// remove water
var city1=built1.and(notwater1);
var city2=built2.and(notwater2);
var city3=built3.and(notwater3);
var city4=built4.and(notwater4);
var city5=built5.and(notwater5);

city1 = city1.where(city1.gt(0),1).where(city1.eq(0),6);
city2 = city2.where(city2.gt(0),2).where(city2.eq(0),6);
city3 = city3.where(city3.gt(0),3).where(city3.eq(0),6);
city4 = city4.where(city4.gt(0),4).where(city4.eq(0),6);
city5 = city5.where(city5.gt(0),5).where(city5.eq(0),6);

var collection=ee.ImageCollection([city1,city2,city3,city4,city5]);
// // // //***********************************show results*******************************************              
var visualization = {bands: ['SR_B5', 'SR_B4', 'SR_B3'],min: 0.0,max: 0.3};
var vizndwi = {min:-1,max:1, gamma:1.5};
var vizndbi = {min:-1,max:1, gamma:1.5};

// Map.addLayer(landsat1.clip(roi.geometry()), visualization, (first_year).toString());
// Map.addLayer(landsat2.clip(roi.geometry()), visualization, (second_year).toString());
// Map.addLayer(landsat3.clip(roi.geometry()), visualization, (third_year).toString());
// Map.addLayer(landsat4.clip(roi.geometry()), visualization, (fourth_year).toString());
// Map.addLayer(landsat5.clip(roi.geometry()), visualization, (fifth_year).toString());
// // // Map.addLayer(ndbi1, vizndbi, 'ndbi1', false);
// // // Map.addLayer(ndbi2, vizndbi, 'ndbi2', false);
// // // Map.addLayer(ndbi3, vizndbi, 'ndbi3', false);
// // // Map.addLayer(ndbi4, vizndbi, 'ndbi4', false);
// // // Map.addLayer(ndbi5, vizndbi, 'ndbi5', false);
// // // Map.addLayer(notwater1, vizndwi, 'water1', false);
// // // Map.addLayer(notwater2, vizndwi, 'water2', false);
// // // Map.addLayer(notwater5, vizndwi, 'water5', false);
// // // Map.addLayer(city1, vizndwi, 'city1', false);
// // // Map.addLayer(city2, vizndwi, 'city2', false);
// // // Map.addLayer(city5, vizndwi, 'city5', false);

var result=collection.min();
Map.addLayer(result,{'min':1,'max':6,'palette':['EA047E','FF6D28','FCE700','00F5FF','00C897','00000000']},'result');


//---------------------------Add the legend!----------------------------------
//添加图例函数                         
function addLegend(palette, names) {  
//图例的底层Panel  
var legend = ui.Panel({style: {position: 'bottom-right', padding: '5px 10px'}});  
//图例标题  
var title = ui.Label({value:'城市化年份',style: {fontWeight: 'bold', color: "red", fontSize: '16px'}});  
legend.add(title);  
//添加每一列图例颜色以及说明  
var addLegendLabel = function(color, name) {  
      var showColor = ui.Label({style: {backgroundColor: '#' + color, padding: '8px', margin: '0 0 4px 0'}});  
      var desc = ui.Label({value: name, style: {margin: '0 0 4px 8px'}});  
      return ui.Panel({widgets: [showColor, desc], layout: ui.Panel.Layout.Flow('horizontal')});  
};  
//添加所有的图例列表  
for (var i = 0; i < palette.length; i++) {  
  var label = addLegendLabel(palette[i], names[i]);  
  legend.add(label);  
}    
Map.add(legend);  
}  
  
//color table & legend name  
var palette = ['EA047E','FF6D28','FCE700','00F5FF','00C897'];  
var names = ["2003","2007","2013",'2018','2022'];  

//添加图例   
addLegend(palette, names);  

// //---------------------------Part 4 compute the morphological index-------------------------------------------------------
var geo=roi.geometry();

// -----------------Project------------------
var citys_Reproject = collection.map(function(city){
  var city_proj=city.reproject('EPSG:32648',null,1000)
  return city_proj
})

// --------------------closed operation ----------------
var kernel = ee.Kernel.circle({radius:500,units:'meters'});//定义一个像素的内核,半径为250m

var citys = citys_Reproject.map(function(city){
  var city_proj=city.focal_max({kernel: kernel, iterations: 2}).focal_min({kernel: kernel, iterations: 2});
  var city_poly = city_proj.reduceToVectors({
        reducer: ee.Reducer.countEvery(), 
        geometry: geo, 
        scale: 1000,
        maxPixels: 1e8})
  var city_area = city_poly.map(function(f0) {
    var areakm = f0.area(1000).divide(1000 * 1000);
    return f0.set({area: areakm});
  });
  var city_largest = city_area.sort("area",false).first();
  
  var perimeterkm = ee.Feature(city_largest).perimeter(1000).divide(1000);  
  var builtWithPerimeter = city_largest.set({perimeter: perimeterkm});  
  var circularity = ee.Number.expression('a*4/(p*p)',{  
    'a': builtWithPerimeter.get('area'),  
    'p': builtWithPerimeter.get('perimeter')  });    
  var builtWithRatio = builtWithPerimeter.set({circularity_ratio: circularity});
  var compactness = ee.Number.expression('2*sqrt(a*3.14159)/p',{  
      'a': builtWithRatio.get('area'),  
      'p': builtWithRatio.get('perimeter')});  
  var builtWithRatio2 = builtWithRatio.set({compactness_ratio: compactness});  

  return builtWithRatio2
})
// print(citys)

Export.table.toDrive({
  collection:ee.FeatureCollection(citys), 
  description:"citys",
  fileFormat: 'SHP'
})




        跑完第一个代码之后,跑第二个代码(就是下面这个).这个代码的改进点在于:为了防止超内存,把代码分成两个部分来跑,第1部分得到城市和乡村的斑块,第2部分计算城市和乡村的温度,并做差得到城市热岛强度。在跑第二部分的时候,把前面半段注释掉,然后把前半段的中间结果import进来。这样子在后半段跑的时候也会更快,同时也不容易超内存。第二个优化的地方在于对矢量的,编号之前是要手动打印查看他的count,再去修改count。现在不用了.

(代码很长,谨慎点开)

// 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
})
print(means)
// -------------------------get each year's 【city】 region(feature)--------------------------
var city1=roi.filter(ee.Filter.eq('label',1)).first();
var city2=roi.filter(ee.Filter.eq('label',2)).first();
var city3=roi.filter(ee.Filter.eq('label',3)).first();
var city4=roi.filter(ee.Filter.eq('label',4)).first();
var city5=roi.filter(ee.Filter.eq('label',5)).first();

// find the city region with dem < 100+mean;
var city_less1 = dem_city.lt(130.48).clip(city1).set("id",2003)  //image,"elevation", int ∈ [0, 1]
var city_less2 = dem_city.lt(125.15).clip(city2).set("id",2008)
var city_less3 = dem_city.lt(126.00).clip(city3).set("id",2013)
var city_less4 = dem_city.lt(126.39).clip(city4).set("id",2018)
var city_less5 = dem_city.lt(117.14).clip(city5).set("id",2022)
var citys = ee.ImageCollection([city_less1,city_less2,city_less3,city_less4,city_less5])
// -------------------------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('label',1)).first()).difference(city1);
var rural2=ee.Feature(rural_citys.filter(ee.Filter.eq('label',2)).first()).difference(city2);
var rural3=ee.Feature(rural_citys.filter(ee.Filter.eq('label',3)).first()).difference(city3);
var rural4=ee.Feature(rural_citys.filter(ee.Filter.eq('label',4)).first()).difference(city4);
var rural5=ee.Feature(rural_citys.filter(ee.Filter.eq('label',5)).first()).difference(city5);
// -------------------------get each year's 【rural(dem<mean+100)】 region (It's 【Image】!!!)--------------------------
var rural_less1 = dem_city.lt(130.48).clip(rural1).set("id",2003);
var rural_less2 = dem_city.lt(125.15).clip(rural2).set("id",2008);
var rural_less3 = dem_city.lt(126.00).clip(rural3).set("id",2013);
var rural_less4 = dem_city.lt(126.39).clip(rural4).set("id",2018);
var rural_less5 = dem_city.lt(117.14).clip(rural5).set("id",2022);

var rurals = ee.ImageCollection([rural_less1,rural_less2,rural_less3,rural_less4,rural_less5])
//Map.addLayer(rural_less1,{min: -10, max: 120, palette: ['green','yellow', 'red']},'rural_less1')
// Map.addLayer(rural_less5, {}, 'rural_less5',false);

// -----------------Convert the rural and city region into the polygon ----------
var fun = function(img){
  var geo = img.reduceToVectors({
        reducer: ee.Reducer.countEvery(), 
        geometry: yuegangao.geometry(), 
        scale: 1000,
        maxPixels: 1e8}) //FeatureCollection (11 elements, 3 columns)
  var id_temp = img.get('id')       
  var addArea = geo.map(function(f0) {
    var areakm = f0.area(1000).divide(1000 * 1000);
    var count_temp = f0.get('count')
    return f0.set({area:areakm,index:count_temp});
    }); // add the properties:area, to eliminate the small polygon
 
  var final = addArea.sort("area",false).first().set('id',id_temp);//select the largest
  return final 
}  

citys=citys.map(fun); //FeatureCollection (5 elements)
rurals=rurals.map(fun); //FeatureCollection (5 elements)
Export.table.toAsset({
  collection:ee.FeatureCollection(citys), 
  description:"citys_temp"})
Export.table.toAsset({
  collection:ee.FeatureCollection(rurals), 
  description:"rurals_temp"})
// Run the above codes and then comment out these codes

//--------------------- calculate the temperature (By MODIS)---------------

var get_start_value=ee.List([2003,2008,2013,2018,2022]).map(function(year){
  var year = ee.Number(year).format("%04d").cat("-01-01");
  var Date_From_YMD = ee.Date(year).millis( );// 可以得到value, 不是用.value()哈!

  return Date_From_YMD
})

var date_sequence= ee.List(get_start_value).map(function(num){
  var start_day=ee.Number(num);
  var end_day=start_day.add(365*24*60*60*1000)
  var num_seq=ee.List.sequence(start_day,end_day,8*24*60*60*1000);
  var date_seq=num_seq.map(function(day_num){
    var date=ee.Date(day_num);
    return date
  })
  return date_seq
})

var date_list=date_sequence.flatten() //reshape the sequence into one dimension
// print(date_list)
var bitwiseExtract = function(input, fromBit, toBit) {
  var maskSize = ee.Number(1).add(toBit).subtract(fromBit);
  var mask = ee.Number(1).leftShift(maskSize).subtract(1);
  return input.rightShift(fromBit).bitwiseAnd(mask);
};

var false_temperature_city = date_list.map(function(day){
  var day = ee.Date(day);
  //---------------------- Select the clip table!!!---------------
  var year = day.get( 'year' );
  var poly = citys.filter(ee.Filter.eq('id',year)).first();
  //-----------------------Load image and clip it! ---------------
  var imgs = ee.ImageCollection("MODIS/061/MYD11A2")
    .filterBounds(poly.geometry()).filterDate(day,day.advance(8,"day"));//is imagecollection
  var size = ee.Number(imgs.size())
  var img = imgs.max();
  var final = img.set('system:time_start',day).set('bandnumber',size).set('city_or_rural',1).clip(ee.Feature(poly).geometry());
    
  return final
  })

var false_temperature_rural = date_list.map(function(day){
  var day = ee.Date(day);
  //---------------------- Select the clip table!!!---------------
  var year = day.get( 'year' );
  var poly = rurals.filter(ee.Filter.eq('id',year)).first();  //-----------------------Load image and clip it! ---------------
  var imgs = ee.ImageCollection("MODIS/061/MYD11A2")
    .filterBounds(poly.geometry()).filterDate(day,day.advance(8,"day"))
  var size = ee.Number(imgs.size())
  var img = imgs.max();
  var final = img.set('system:time_start',day).set('bandnumber',size).set('city_or_rural',2).clip(ee.Feature(poly).geometry());   
  return final
  })
// print('city',false_temperature_city)
// print('rural',false_temperature_rural) // both are List (138 elements)

false_temperature_city=ee.ImageCollection(false_temperature_city).filterMetadata('bandnumber','greater_than',0)
false_temperature_rural=ee.ImageCollection(false_temperature_city).filterMetadata('bandnumber','greater_than',0)
// print(false_temperature_city,"collection") //ImageCollection (129 elements),->Image (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 = citys.filter(ee.Filter.eq('id',year)).first(); 
  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,
  });
  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,
  });
  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);
})
// print(qc_account_city)
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 = rurals.filter(ee.Filter.eq('id',year)).first(); 
  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 = citys.filter(ee.Filter.eq('id',year)).first(); 
  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 = rurals.filter(ee.Filter.eq('id',year)).first(); 
  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})  
}));  
Export.table.toDrive({
  collection: data,
  description: 'xianggang_uhi',
  fileFormat: 'CSV',
});

// // var chart_day = ui.Chart.feature.byFeature(data.sort('time').filterMetadata('year','equals',2013),'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',2013),'time','UHI_night')  
// //                       .setChartType('ColumnChart')  
// //                       .setOptions({  
// //                         title: '夜间城市热岛强度',  
// //                         hAxis: {title: 'Date'},  
// //                         vAxis: {title: 'UHI'}  
// //                       }); 

// // print(chart_day);
// // print(chart_night);



############################### 分 界 线 ################################

原回答:

        今天的内容是复制本人自己的实验报告,放心食用。最后放全部代码!如果不想看前面的东西就直接拉到后面!前面的代码懒得一个一个插代码段了,要复制的拉到最后去复制。本篇涵盖了之前写的好几篇博客的内容。

一.实验目的与数据

       计算粤港澳城市群2005,2015,和2022三年的城市热岛强度。

       使用的数据为MODIS_061_MYD11A2,即Aqua拍摄的地表温度数据,过境时间约为下午1:30和凌晨1:30。

二.实验流程图

三.实验步骤

  1. 研究区域斑块制作

  • 去除水体

在上一次不透水面提取的实验基础上,基于不透水面的斑块,计算这个斑块范围内的MNDWI(如图1),设置阈值为0,筛选出MNDWI<0的区域。代码如下,其中的and运算就做了一个不透水面和非水体的区域取交集的运算。

图 1 MNDWI计算结果

  1. // set thresold for built by MNDWI  
  2. var notwater5 = mndwi5.lt(mndwi_t).clipToCollection(roi);  
  3. notwater5=notwater5.mask(notwater5);  
  4. var notwater4 = mndwi4.lt(mndwi_t).clipToCollection(roi);  
  5. notwater4=notwater4.mask(notwater4);  
  6. var notwater3 = mndwi3.lt(mndwi_t).clipToCollection(roi);  
  7. notwater3=notwater3.mask(notwater3);  
  8.   
  9. // remove water  
  10. var city3=built3.and(notwater3);  
  11. var city4=built4.and(notwater4);  
  12. var city5=built5.and(notwater5);  
  • 不透水面转矢量

        转矢量使用的是reduceToVectors函数,同时给转好的矢量添加面积字段。因为转之后的向量一般有好几个,其中只有一个是最大的,基本涵盖了原始image的全部范围。所以之后根据面积筛选最大的斑块。因为大部分代码和上一次实验相同,就不展示了,最后是哟女export函数导出结果,命名为city,这个collection是3年的城市矢量,一年一个。详见我写的博客:http://t.csdn.cn/MeoJY

  1. Export.table.toAsset({  
  2.   collection:ee.FeatureCollection(citys),   
  3.   description:"citys"})  

  • 计算矢量边界内的高程均值(包括城市和乡村)

         计算UHI需要剔除高程的影响。下面的代码只需要运行一次,就可以得到研究区域的DEM的均值。筛选出研究区域内高程在均值±100m范围内的部分。具体的reduceRegion求均值的解释可以看我的这一篇博客:http://t.csdn.cn/BwqqJ

  1. var dem_city = DEM.select('elevation')  
  2. //---------- calculate the mean dem (Just run once!) ----------  
  3. var means = roi.map(function(roi){  
  4.   var rural_city = roi.buffer(5000,1000);  
  5.   var meanDict = dem_city.reduceRegion({  
  6.     reducer: ee.Reducer.mean(),  
  7.     geometry:rural_city.geometry(),   
  8.     scale: 1000,  
  9.     maxPixels: 1e9  
  10.   });  
  11.   var dem_mean = ee.Image.constant(meanDict.values());  
  12.   // find the region where elev is larger than the mean value of the total study area  
  13.   return dem_mean  // 2005:mean:21.54201520.85202221.53  
  14. })  
  • 排除掉高于高程100m以上的区域,做掩膜

        下面的lt()函数内部就是每一年研究区域均值+100m的结果,因为研究区域没有高程-100m的地方,所以就不做下限的约束。

  1. // find the city region with dem < 100+mean;  
  2. var city_less1 = dem_city.lt(121.54).clip(city1)  //image,"elevation", int  [0, 1]  
  3. var city_less2 = dem_city.lt(120.84).clip(city2)  
  4. var city_less3 = dem_city.lt(121.53).clip(city3)  
  5. var citys = ee.ImageCollection([city_less1,city_less2,city_less3]) 

  • 得到三年城市和乡村的矢量边界

这里直接选取了5km作为缓冲区半径,往外做5km的缓冲区。得到了乡村和城市的区域之和。为了得到纯乡村,用缓冲区.difference(城市)就可以得到去掉了城市区域的缓冲区,即乡村。同理,对乡村也做高程的约束。

  1. // -------------------------get each year's rural+city region--------------------------  
  2. var rural_citys = roi.map(function(roi){  
  3.   var rural_city = roi.buffer(5000,1000);  
  4.   return rural_city// Feature, with 8 properties  
  5. })  
  6.   
  7. // -------------------------get each year's rural region--------------------------  
  8. var rural1=ee.Feature(rural_citys.filter(ee.Filter.eq('ID',1)).first()).difference(city1);  
  9. var rural2=ee.Feature(rural_citys.filter(ee.Filter.eq('ID',2)).first()).difference(city2);  
  10. var rural3=ee.Feature(rural_citys.filter(ee.Filter.eq('ID',3)).first()).difference(city3);  
  11.   
  12. // -------------------------get each year's rural(dem<mean+100) region (It's Image!!!)--------------------------  
  13. var rural_less1 = dem_city.lt(121.54).clip(rural1);// image, with one band: "elevation", int  [0, 1]   
  14. var rural_less2 = dem_city.lt(120.84).clip(rural2);  
  15. var rural_less3 = dem_city.lt(121.53).clip(rural3);  
  16. var rurals = ee.ImageCollection([rural_less1,rural_less2,rural_less3])  

2. 制作时间序列影像集

1)生成等间隔的时间序列

         现在开始使用MODIS的LST数据,计算城市和乡村的一段时间序列中的日夜平均温度。这一大节“2.制作时间序列影像集”具体解释可以看我写的这一篇博客:http://t.csdn.cn/71SdO。5年总共有138景影像。

图 2 得到一定时间序列的影像集

  1. var get_start_value=ee.List([2005,2015,2022]).map(function(year){  
  2.   var year = ee.Number(year).format("%04d").cat("-01-01");  
  3.   var Date_From_YMD = ee.Date(year).millis( );// 可以得到value, 不是用.value()哈!  
  4.   
  5.   return Date_From_YMD  
  6. })  
  7.   
  8. var date_sequence= ee.List(get_start_value).map(function(num){  
  9.   var start_day=ee.Number(num);  
  10.   var end_day=start_day.add(365*24*60*60*1000)  
  11.   var num_seq=ee.List.sequence(start_day,end_day,8*24*60*60*1000);  
  12.   var date_seq=num_seq.map(function(day_num){  
  13.     var date=ee.Date(day_num);  
  14.     return date  
  15.   })  
  16.   return date_seq  
  17. })  
  18. // print(date_sequence)  
  19.   
  20. var date_list=date_sequence.flatten() //reshape the sequence into one dimension 

2)根据时间序列和研究范围得到全部可能的影像

  1. var false_temperature_city = date_list.map(function(day){  
  2.   var day = ee.Date(day);  
  3.   //---------------------- Select the clip table!!!---------------  
  4.   var year = day.get( 'year' );  
  5.   var city_poly=ee.Algorithms.If(ee.Number(year).eq(2005),city1,(ee.Algorithms.If(ee.Number(year).eq(2015),city2,city3))); // city  
  6.   
  7.   //-----------------------Load image and clip it! ---------------  
  8.   var imgs = ee.ImageCollection("MODIS/061/MYD11A2")  
  9.     .filterBounds(table).filterDate(day,day.advance(8,"day"));//is imagecollection  
  10.   var size = ee.Number(imgs.size())  
  11.   var img = imgs.max();  
  12.   var final = img.set('system:time_start',day).set('bandnumber',size).set('city_or_rural',1).clip(ee.Feature(city_poly).geometry());  
  13.       
  14.   return final  
  15.   })  
  16. var false_temperature_rural = date_list.map(function(day){  
  17.   var day = ee.Date(day);  
  18.   //---------------------- Select the clip table!!!---------------  
  19.   var year = day.get( 'year' );  
  20.   var rural_poly=ee.Algorithms.If(ee.Number(year).eq(2005),rural1,(ee.Algorithms.If(ee.Number(year).eq(2015),rural2,rural3))); // rural  
  21.   //-----------------------Load image and clip it! ---------------  
  22.   var imgs = ee.ImageCollection("MODIS/061/MYD11A2")  
  23.     .filterBounds(table).filterDate(day,day.advance(8,"day"))  
  24.   var size = ee.Number(imgs.size())  
  25.   var img = imgs.max();  
  26.   var final = img.set('system:time_start',day).set('bandnumber',size).set('city_or_rural',2).clip(ee.Feature(rural_poly).geometry());     
  27.   return final  
  28.   }) 

3)筛选掉空的影像

  1. false_temperature_city=ee.ImageCollection(false_temperature_city).filterMetadata('bandnumber','greater_than',0)  
  2. false_temperature_rural=ee.ImageCollection(false_temperature_city).filterMetadata('bandnumber','greater_than',0)  

3.温度转摄氏度

1) 温度转摄氏度

MODIS的LST数据的温度是开尔文温度,需要转成摄氏度。代码里面的false_temperature 代指开尔文温度,而tru_temperature代指摄氏度。计算公式是:真实的地表温度 = MODIS中的地表温度*0.02-273.15;之后我们把每一天的早晚温度算出来,加在属性中。

  1. // ---------Control the quality and Convert temperature to Celsius.-------------------  
  2. var convert = function(img){  
  3.   var img = ee.Image(img)  
  4.   var date = img.get('system:time_start');   
  5.   //control the quality  
  6.   var lstDay = img.select('LST_Day_1km');  
  7.   var lstNight = img.select('LST_Night_1km');  
  8.   var qcDay = img.select('QC_Day');  
  9.   var qcNight = img.select('QC_Night');  
  10.     
  11.   // ---------calculate the Celsius------------------------------------------  
  12.   var day_wendu = lstDay.multiply(0.02).subtract(273.15);  
  13.   var night_wendu = lstNight.multiply(0.02).subtract(273.15);  
  14.   var final = qcDay.addBands(day_wendu).addBands(night_wendu).addBands(qcNight).set('system:time_start',date);  
  15.     
  16.   return final;  
  17. };  

2) 质量控制函数,求出高质量像元面积占整个研究范围的面积:

        对于数据需要做一下质量控制,筛选出受云的影响较小,且成像质量高的影像。下面的函数可以提取指定位置qc二进制码。

        注意这个函数只能接受QC波段为int类型,不可为double,如果前面从imagecollection筛选影像的时候用到了median或者mean,就会把影像的全部波段都变成double类型,包括QC波段。因此,前面为了将imagecollection中唯一的那一个影像转成image,要使用max或者min。

  1. var bitwiseExtract = function(input, fromBit, toBit) {  
  2.   var maskSize = ee.Number(1).add(toBit).subtract(fromBit);  
  3.   var mask = ee.Number(1).leftShift(maskSize).subtract(1);  
  4.   return input.rightShift(fromBit).bitwiseAnd(mask);  
  5. };  

        然后将城市和乡村的时间序列影像集都过一遍这个函数,得到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);
})

3) 筛选高质量像元占比大于10%的影像

  1. var qc_tru_city = qc_account_city.filter(ee.Filter.gt('day_account',10)).filter(ee.Filter.gt('night_account',10));  
  2. var qc_tru_rural = qc_account_rural.filterMetadata('day_account','greater_than',10).filterMetadata('night_account','greater_than',10); 

4. 计算温度均值

1) 计算温度均值并添加到属性中。仅展示城市的,乡村同理。

  1. var city_means_wendu = qc_tru_city.map(function(img){  
  2.   var day = img.get('system:time_start');  
  3.   var year = ee.Date(day).get( 'year' );  
  4.   var city_poly=ee.Algorithms.If(ee.Number(year).eq(2005),city1,(ee.Algorithms.If(ee.Number(year).eq(2015),city2,city3))); // city  
  5.   var meanDict = img.reduceRegion({  
  6.     reducer: ee.Reducer.mean(),  
  7.     geometry:ee.Feature(city_poly).geometry(),   
  8.     scale: 1000,  
  9.     maxPixels: 1e9  
  10.   });  
  11.   var mean_day = meanDict.values().get(0);  
  12.   var mean_night = meanDict.values().get(1);    
  13.   var mean = img.set('mean_day',mean_day).set('mean_night',mean_night);  
  14.     
  15.   // var mean = img.set('mean_day',meanDict.values());  
  16.   return mean   
  17. }) 

2) 匹配同一时刻的乡村和城市计算结果,求UHI

        将城市和乡村的每期影像的平均温度求出后,需要匹配同一拍摄时间的城市和乡村的影像。这里用到了join,它有点像是数据库的操作,没有改变原始数据,而是生成了一个新的collection,将两个数据关联了起来,这里是直接把两个数据同等级地存在了一起,用的函数是ee.Join.inner,如果用其他的函数join出来的结果是有包含关系的。

  1. //----------------- join the city and the rural imagecollection-----------------------------  
  2. var join_filter = ee.Filter.equals({  
  3.     // difference: One_Day_Millis,  
  4.     leftField: 'system:time_start',  
  5.     rightField: 'system:time_start'  
  6.   })  
  7.   
  8. var Inner_Join = ee.Join.inner('primary''secondary');// 定义一个invertJoin  
  9. var Inner_Join_Results = Inner_Join.apply(city_means_wendu, rural_means_wendu, join_filter);// 应用invertJoin  
  10. // print('Inner_Join_Results: ', Inner_Join_Results);  
  11.   
  12. var joined = Inner_Join_Results.map(function(feature) {  
  13.   var city = feature.get('primary');  
  14.   var rural = feature.get('secondary');  
  15.   var city_wendu_day = ee.Feature(city).get('mean_day');  
  16.   var city_wendu_night = ee.Feature(city).get('mean_night');  
  17.   var rural_wendu_day = ee.Feature(rural).get('mean_day');  
  18.   var rural_wendu_night = ee.Feature(rural).get('mean_night');  
  19.   var uhiday = ee.Number(city_wendu_day).subtract(ee.Number(rural_wendu_day));  
  20.   var uhinight = ee.Number(city_wendu_night).subtract(ee.Number(rural_wendu_night));    
  21.   var final = ee.Image.cat(feature.get('primary'), feature.get('secondary'))  
  22.     .set('uhiday',uhiday).set('uhinight',uhinight);  
  23.       
  24.   return final  
  25. })  

5. 作图

1) 直方图制作

        这里用的是ui.Chart.feature.byFeature来做图,参数分别为需要作图的数据,横坐标数据(属性名),纵坐标数据(属性名)。制作的是直方图。

  1. // --------------------出图 --------------------
  2. var data = ee.FeatureCollection(joined.map(function(img) {    
  3.   var day = img.get('system:time_start');  
  4.   var year = ee.Date(day).get( 'year' );  
  5.   return ee.Feature(null,{time:day,UHI_day:img.get('uhiday'),UHI_night:img.get('uhinight'),year:year})    
  6. }));    
  7.   
  8. var chart_day = ui.Chart.feature.byFeature(data.sort('time').filterMetadata('year','equals',2005),'time','UHI_day')    
  9.                       .setChartType('ColumnChart')    
  10.                       .setOptions({    
  11.                         title: '白天城市热岛强度',    
  12.                         hAxis: {title: 'Date'},    
  13.                         vAxis: {title: 'UHI'}    
  14.                       });   
  15.                         
  16. var chart_night = ui.Chart.feature.byFeature(data.sort('time').filterMetadata('year','equals',2005),'time','UHI_night')    
  17.                       .setChartType('ColumnChart')    
  18.                       .setOptions({    
  19.                         title: '夜间城市热岛强度',    
  20.                         hAxis: {title: 'Date'},    
  21.                         vAxis: {title: 'UHI'}    
  22.                       });   
  23.   
  24. print(chart_day);  
  25. print(chart_night); 

        效果如下图所示:

       综合三年的结果,如下图所示:可以看出,白天的城市热岛强度普遍低于夜间。

        季节方面。虽然夏季的高质量影响较少,但可以看出白天城市热岛强度在夏季最强,从八月份之后逐渐减弱,八月后的热岛强度有非常线性的关系。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(dem<mean+100)】 region (It's 【Image】!!!)--------------------------
var rural_less1 = dem_city.lt(121.54).clip(rural1);// image, with one band: "elevation", int ∈ [0, 1] 
var rural_less2 = dem_city.lt(120.84).clip(rural2);
var rural_less3 = dem_city.lt(121.53).clip(rural3);
var rurals = ee.ImageCollection([rural_less1,rural_less2,rural_less3])
//Map.addLayer(rural_less1,{min: -10, max: 120, palette: ['green','yellow', 'red']},'rural_less1')

// -----------------Convert the rural and city region into the polygon ----------
var fun = function(img){
  var geo = img.reduceToVectors({
        reducer: ee.Reducer.countEvery(), 
        geometry: yuegangao.geometry(), 
        scale: 1000,
        maxPixels: 1e8}) //FeatureCollection (11 elements, 3 columns)
        
  var addArea = geo.map(function(f0) {
    var areakm = f0.area(1000).divide(1000 * 1000);
    var count_temp = f0.get('count')
    return f0.set({area:areakm,index:count_temp});
    }); // add the properties:area, to eliminate the small polygon
    
  var final = addArea.sort("area",false).first();//select the largest
  return final 
}  
var citys_geo=citys.map(fun); //FeatureCollection (3 elements)
var rurals_geo=rurals.map(fun); //FeatureCollection (3 elements)

var old_label1 = ee.List([7535,7974,8297]);
var new_label1 = ee.List([2005,2015,2022]);
var old_label2 = ee.List([9593,9698,9922]);
var new_label2 = ee.List([2005,2015,2022]);

var city_remap = citys_geo.remap(old_label1,new_label1,'index');
var rural_remap = rurals_geo.remap(old_label2,new_label2,'index');
// print(rural_remap)
var city1 = city_remap.filterMetadata('index','equals',2005).first();
var city2 = city_remap.filterMetadata('index','equals',2015).first();
var city3 = city_remap.filterMetadata('index','equals',2022).first();
var rural1 = rural_remap.filterMetadata('index','equals',2005).first();
var rural2 = rural_remap.filterMetadata('index','equals',2015).first();
var rural3 = rural_remap.filterMetadata('index','equals',2022).first();
// // print(rural3) //Feature 2 (Polygon, 4 properties)
// //--------------------- calculate the temperature (By MODIS)---------------

var get_start_value=ee.List([2005,2015,2022]).map(function(year){
  var year = ee.Number(year).format("%04d").cat("-01-01");
  var Date_From_YMD = ee.Date(year).millis( );// 可以得到value, 不是用.value()哈!

  return Date_From_YMD
})

var date_sequence= ee.List(get_start_value).map(function(num){
  var start_day=ee.Number(num);
  var end_day=start_day.add(365*24*60*60*1000)
  var num_seq=ee.List.sequence(start_day,end_day,8*24*60*60*1000);
  var date_seq=num_seq.map(function(day_num){
    var date=ee.Date(day_num);
    return date
  })
  return date_seq
})
// print(date_sequence)

var date_list=date_sequence.flatten() //reshape the sequence into one dimension
//print(date_list)
// var city_poly=ee.Algorithms.If(ee.Number(2022).eq(2005),city1,(ee.Algorithms.If(ee.Number(2022).eq(2015),city2,city3))); // city
// print(ee.Feature(city_poly).geometry())

var bitwiseExtract = function(input, fromBit, toBit) {
  var maskSize = ee.Number(1).add(toBit).subtract(fromBit);
  var mask = ee.Number(1).leftShift(maskSize).subtract(1);
  return input.rightShift(fromBit).bitwiseAnd(mask);
};

var false_temperature_city = date_list.map(function(day){
  var day = ee.Date(day);
  //---------------------- Select the clip table!!!---------------
  var year = 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

  //-----------------------Load image and clip it! ---------------
  var imgs = ee.ImageCollection("MODIS/061/MYD11A2")
    .filterBounds(table).filterDate(day,day.advance(8,"day"));//is imagecollection
  var size = ee.Number(imgs.size())
  var img = imgs.max();
  var final = img.set('system:time_start',day).set('bandnumber',size).set('city_or_rural',1).clip(ee.Feature(city_poly).geometry());
    
  return final
  })
var false_temperature_rural = date_list.map(function(day){
  var day = ee.Date(day);
  //---------------------- Select the clip table!!!---------------
  var year = 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))); // rural
  //-----------------------Load image and clip it! ---------------
  var imgs = ee.ImageCollection("MODIS/061/MYD11A2")
    .filterBounds(table).filterDate(day,day.advance(8,"day"))
  var size = ee.Number(imgs.size())
  var img = imgs.max();
  var final = img.set('system:time_start',day).set('bandnumber',size).set('city_or_rural',2).clip(ee.Feature(rural_poly).geometry());   
  return final
  })
// print('city',false_temperature_city)
// print('rural',false_temperature_rural) // both are List (138 elements)

false_temperature_city=ee.ImageCollection(false_temperature_city).filterMetadata('bandnumber','greater_than',0)
false_temperature_rural=ee.ImageCollection(false_temperature_city).filterMetadata('bandnumber','greater_than',0)
// print(false_temperature_city,"collection") //ImageCollection (129 elements),->Image (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);

猜你喜欢

转载自blog.csdn.net/weixin_46812066/article/details/127855676
今日推荐