Google earth engine (GEE): Calculate the urban heat island intensity (UHI) of a certain time series based on LST (land surface temperature data) of MODIS, and draw a histogram

2023.01.06 update:

        The complete process is as follows. First, the first code can get urban patches, and the second code can calculate the intensity of urban heat island effect in this area. A friend sent a private message to ask for all the codes, and at the same time, I modified the code to calculate the intensity of urban heat island Some of the more cumbersome places, move out the latest code (the code of the original answer is no problem! I just optimized it):

        The first code (the code is very long, click carefully):

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'
})




        After running the first code, run the second code (the one below). The improvement of this code is: in order to prevent over-memory, the code is divided into two parts to run, and the first part gets urban and rural plaques , the second part calculates the urban and rural temperature, and makes the difference to get the urban heat island intensity. When running the second part, comment out the first half, and then import the intermediate results of the first half. In this way, it will be faster in the second half of the run, and it is not easy to exceed the memory. The second optimization is for the vector. Before numbering, you need to manually print and check its count, and then modify the count. Not anymore.

(The code is very long, click carefully)

// 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);



################################ Boundary ################## ################

Original answer:

        Today's content is to copy my own experimental report, so you can eat it with confidence. Finally put all the code ! If you don't want to see what's in front, just pull it to the back! The previous code is too lazy to insert code segments one by one, and the ones to be copied will be copied at the end . This article covers the content of several blogs written before.

one. Experimental purpose and data

       Calculate the urban heat island intensity of the Guangdong-Hong Kong-Macao urban agglomeration in 2005, 2015, and 2022.

       The data used is MODIS_061_MYD11A2, which is the surface temperature data taken by Aqua, and the transit time is about 1:30 pm and 1:30 am.

two. Experiment flow chart

three. Experimental procedure

  1. Plaque making in the study area

  • remove water body

On the basis of the last experiment of impermeable surface extraction, based on the impermeable surface patch, calculate the MNDWI within the patch range (as shown in Figure 1), set the threshold to 0, and screen out the area with MNDWI<0. The code is as follows, in which the and operation performs an intersection operation of an impermeable surface and a non-water body area.

Figure 1 MNDWI calculation results

  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);  
  • Impervious surface to vector

        The vector is converted using the reduceToVectors function, and an area field is added to the converted vector. Because there are generally several vectors after conversion, only one of which is the largest, basically covering the entire range of the original image. So then filter the largest patch based on area. Because most of the code is the same as the last experiment, it will not be shown. Finally, the export function of yo is the result, named city. This collection is a city vector for 3 years, one for each year. See my blog for details: http://t.csdn.cn/MeoJY .

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

  • Computes elevation mean within vector boundaries (both urban and rural)

         Calculation of UHI needs to remove the influence of elevation. The following code only needs to be run once to get the mean value of the DEM of the study area. Filter out the part of the study area whose elevation is within the mean ±100m range. For an explanation of the mean value of reduceRegion, you can read my blog: 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. })  
  • Exclude the area above the elevation of 100m and make a mask

        The interior of the lt() function below is the result of the average value of +100m in the study area every year, because there is no place with an elevation of -100m in the study area, so there is no lower limit constraint.

  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]) 

  • Get three years of city and country vector boundaries

Here, 5km is directly selected as the radius of the buffer zone, and a buffer zone of 5km is made outside. The sum of the rural and urban areas is obtained. In order to get the pure countryside, use buffer.difference(city) to get the buffer zone without the urban area, that is, the countryside. In the same way, elevation constraints are also applied to villages.

  1. // -------------------------get each year's rural+city region--------------------------  
  2. var  rural_cities = 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=yes.Feature(rural_citys.filter(yes.Filter.eq( 'ID' ,1)).first()).difference(city1);  
  9. var  rural2=yes.Feature(rural_citys.filter(yes.Filter.eq( 'ID' ,2)).first()).difference(city2);  
  10. var  rural3=yes.Feature(rural_citys.filter(yes.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. Make a time series image set

1) Generate an equally spaced time series

         Now start using the LST data from MODIS to calculate the average day and night temperature in a time series of urban and rural areas. For a detailed explanation of this big section "2. Making a Time Series Image Collection", you can read this blog I wrote: http://t.csdn.cn/71SdO. There are a total of 138 images in 5 years.

Figure 2 Obtaining an image set of a certain time series

  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( ); //  You can get the value  instead of using .value () ha!  
  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) Obtain all possible images according to time series and research scope

  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) Filter out empty images

  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. Convert temperature to Celsius

1) Convert temperature to Celsius

The temperature of MODIS LST data is Kelvin temperature, which needs to be converted into Celsius. The false_temperature in the code refers to Kelvin temperature, and tru_temperature refers to Celsius. The calculation formula is: real surface temperature = surface temperature in MODIS * 0.02-273.15; then we calculate the morning and evening temperature of each day and add it to the attribute.

  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) Quality control function, to calculate the area of ​​the high-quality pixel area in the entire research area:

        For the data, it is necessary to do some quality control to filter out images that are less affected by clouds and have high imaging quality. The following function can extract the qc binary code at the specified position.

        Note that this function can only accept QC band as int type, not double. If median or mean is used when filtering images from imagecollection, all bands of the image will be changed to double type, including QC band. Therefore, in order to convert the only image in the image collection into an image, use max or 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. };  

        Then pass this function through the time series image sets of both urban and rural areas to get the number of the specified bit position of the QC band. According to MODIS_GEE's guidelines, we need to extract the code below to show only urban image sets, and the same for rural areas.

Figure 3 GEE's description of each band of MODIS data

Figure 4 The meaning of each bit in the QC_DAY band

// 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) Filter images with high-quality pixels accounting for more than 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. Calculating the average temperature

1) Calculate the temperature mean and add it to the attribute. If only cities are shown, the same applies to villages.

  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) Match the calculation results of villages and cities at the same time, and find UHI

        After calculating the average temperature of each image of the city and the countryside, it is necessary to match the images of the city and the countryside at the same shooting time. Join is used here, which is a bit like a database operation. Instead of changing the original data, a new collection is generated to associate the two data. Here, the two data are directly stored together at the same level. Use The function is ee.Join.inner, if you use other functions to join, the result has an inclusion relationship.

  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' ); //  Define an 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. Drawing

1) Histogram creation

        Here, ui.Chart.feature.byFeature is used to make the graph, and the parameters are the data to be graphed, the abscissa data (attribute name), and the ordinate data (attribute name). What is produced is a histogram.

  1. // -------------------- Picture  --------------------
  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:  ' Daytime Urban Heat Island Intensity ' ,    
  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:  ' Urban heat island intensity at night ' ,    
  20.                         hAxis: {title: 'Date'},    
  21.                         vAxis: {title: 'UHI'}    
  22.                       });   
  23.   
  24. print(chart_day);  
  25. print(chart_night); 

        Results as shown below:

       The results of the three years are combined, as shown in the figure below: It can be seen that the urban heat island intensity during the day is generally lower than that at night.

        seasonal aspect. Although the influence of high quality in summer is less, it can be seen that the urban heat island intensity during the day is the strongest in summer, and gradually weakens after August, and the heat island intensity after August has a very linear relationship. The urban heat island intensity in the spring and summer of 2005 and 2015 did not change significantly with the seasons, but in 2022, the urban heat island intensity showed a clear upward trend with the increase of the month. However, the intensity of the nocturnal heat island has irregular monthly and seasonal changes.

Figure 5. Urban heat island intensity in day and night for three years, (a)(b) in 2005, (c)(d) in 2015, (e)(f) in 2022

Interannual variability. Judging from the overall trend, the intensity of heat island is increasing year by year, and the growth rate is relatively stable. 2015 has the maximum and minimum values ​​in three years, and the degree of dispersion is also the largest. It is also the only year with negative heat island intensity during the day.

        The mean value of nighttime heat island intensity fluctuates with the increase of the year, but the median and maximum value increase slightly. The minimum value still occurs in 2015, but the maximum value occurs in 2022. The visual estimation with the largest degree of dispersion is still in 2015.

  [Code giveaway! The following code is very long, click carefully]

// 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);

Guess you like

Origin blog.csdn.net/weixin_46812066/article/details/127855676