This tutorial shows how to extract event-month climate variables and DEM-derived slope for GLOF or glacial-lake points using Google Earth Engine, then download the result directly as a CSV without using the Tasks tab or Google Drive export.
What we are extracting
The input table contains one row per GLOF or glacial-lake event. For every row, the code reads the event year, event month, longitude, and latitude. It then pulls climate data for that exact year-month and slope from a DEM at the coordinate.
| Output variable | Meaning | Unit |
|---|---|---|
Monthly_Rainfall_Event_Month_mm |
Total accumulated precipitation during the event month | mm/month |
Mean_Daily_Rainfall_Event_Month_mm_per_day |
Monthly rainfall divided by number of days in the event month | mm/day |
Mean_Monthly_Temperature_Event_Month_C |
Mean 2 m air temperature of the event month | °C |
Mean_Monthly_Surface_Pressure_Event_Month_hPa |
Mean surface pressure of the event month | hPa |
Slope_degree |
DEM-derived local terrain slope at the exact coordinate pixel | degree |
Slope_percent |
Slope converted from degree to percent | % |
Datasets and GEE functions used
The workflow uses public datasets available in Google Earth Engine. Climate variables come from ERA5-Land monthly aggregated data. Slope is calculated from Copernicus DEM GLO-30 using the Earth Engine terrain slope function.
| Variable extracted | GEE dataset / function | GEE ID / link | Purpose |
|---|---|---|---|
| Monthly rainfall | ERA5-Land Monthly Aggregated | ECMWF/ERA5_LAND/MONTHLY_AGGR |
Event-month accumulated precipitation |
| Mean monthly temperature | ERA5-Land Monthly Aggregated | ECMWF/ERA5_LAND/MONTHLY_AGGR |
Event-month mean 2 m temperature |
| Mean monthly surface pressure | ERA5-Land Monthly Aggregated | ECMWF/ERA5_LAND/MONTHLY_AGGR |
Event-month mean surface pressure |
| Slope | Copernicus DEM GLO-30 + ee.Terrain.slope() |
COPERNICUS/DEM/GLO30ee.Terrain.slope(dem)
|
Slope in degrees from the DEM at the coordinate pixel |
| Direct CSV download | FeatureCollection download URL | getDownloadURL() |
Creates a direct CSV download link without running an export task |
How the event-month climate extraction works
For each event, the date is used to select the matching year and month. The selected month is not a long-term climatology; it is the exact event year-month.
Event row: 2024/8/16 at longitude 86.57, latitude 27.83
↓
Event month selected: 2024-08-01 to 2024-09-01
↓
ERA5-Land monthly image selected: August 2024
↓
Extract rainfall, temperature, and surface pressure at that coordinate
| Event date | Month used in GEE | Meaning |
|---|---|---|
| 1977/9/3 | September 1977 | Climate variables from September 1977 |
| 1980/6/23 | June 1980 | Climate variables from June 1980 |
| 2025/7/8 | July 2025 | Climate variables from July 2025 |
How rainfall, temperature, and pressure are calculated
In ERA5-Land monthly aggregated data, precipitation is a flow variable and is provided as a monthly accumulated value. Temperature and surface pressure are non-flow variables and are provided as monthly mean values. The code therefore treats rainfall differently from temperature and pressure.
| Variable | ERA5 band | ERA5 unit | Calculation in code | Final unit |
|---|---|---|---|---|
| Monthly rainfall | total_precipitation_sum |
m/month | × 1000 |
mm/month |
| Mean daily rainfall | derived from monthly rainfall | mm/month | monthly rainfall / days in month |
mm/day |
| Mean monthly temperature | temperature_2m |
K | - 273.15 |
°C |
| Mean monthly surface pressure | surface_pressure |
Pa | / 100 |
hPa |
How slope is calculated
Slope is calculated from a DEM, not from ERA5. The code loads Copernicus DEM GLO-30 and applies ee.Terrain.slope(). The output is a slope raster in degrees. The slope value is then sampled at each coordinate.
North pixel
ZN
West pixel Center pixel East pixel
ZW target point ZE
ZS
South pixel
Conceptually:
East-West gradient = change from west to east
North-South gradient = change from south to north
Final slope combines both directional gradients.
The exact internal implementation is handled by Earth Engine. Conceptually, local slope is based on elevation differences between neighboring pixels. The percent slope is then calculated from the degree slope as:
Slope_percent = tan(Slope_degree × π / 180) × 100
Step-by-step GEE code explanation
Step 1: Prepare the point table
GEE uses coordinate order as [longitude, latitude]. The event year and event month are stored as properties so that every row can be processed independently.
var inputData = [
[1, 'Nae', 1977, 9, '3', 86.84, 27.83],
[2, 'Nagma Pokhari Phuchan', 1980, 6, '23', 87.87, 27.87]
];
var points = ee.FeatureCollection(inputData.map(function(row) {
return ee.Feature(ee.Geometry.Point([row[5], row[6]]), {
'Point_ID': row[0],
'Glacier_Lake_Name': row[1],
'Event_Year': row[2],
'Event_Month': row[3],
'Event_Day': row[4],
'Longitude': row[5],
'Latitude': row[6]
});
}));
Step 2: Select the ERA5-Land monthly image for the event month
For each row, monthStart and monthEnd are created from the event year and event month. Then only the matching ERA5 monthly image is selected.
var era5Month = ee.ImageCollection('ECMWF/ERA5_LAND/MONTHLY_AGGR')
.filterDate(monthStart, monthEnd)
.select([
'total_precipitation_sum',
'temperature_2m',
'surface_pressure'
])
.first();
Step 3: Convert climate units
Precipitation is converted from meters to millimeters. Temperature is converted from Kelvin to Celsius, and surface pressure from Pascal to hPa.
var monthlyRainfallMM = era5Month.select('total_precipitation_sum')
.multiply(1000)
.rename('Monthly_Rainfall_Event_Month_mm');
var meanDailyRainfallMM = monthlyRainfallMM
.divide(ee.Image.constant(daysInMonth))
.rename('Mean_Daily_Rainfall_Event_Month_mm_per_day');
var temperatureC = era5Month.select('temperature_2m')
.subtract(273.15)
.rename('Mean_Monthly_Temperature_Event_Month_C');
var pressureHPA = era5Month.select('surface_pressure')
.divide(100)
.rename('Mean_Monthly_Surface_Pressure_Event_Month_hPa');
Step 4: Calculate slope from DEM
The DEM is used only to derive slope in this version. The slope is exported in both degrees and percent.
var dem = ee.ImageCollection('COPERNICUS/DEM/GLO30')
.select('DEM')
.mosaic();
var slopeDegree = ee.Terrain.slope(dem)
.rename('Slope_degree');
var slopePercent = slopeDegree
.multiply(Math.PI)
.divide(180)
.tan()
.multiply(100)
.rename('Slope_percent');
Step 5: Create a direct CSV download link
Instead of using Tasks → Run → Google Drive, the code creates a direct CSV URL using getDownloadURL(). This is useful for small to moderate tables such as point-based GLOF inventories.
var csvUrl = extracted.getDownloadURL({
format: 'CSV',
filename: 'GLOF_Nepal_EventMonth_Climate_Slope_Clean',
selectors: selectors
});
print('DIRECT CSV DOWNLOAD URL:', csvUrl);
Complete final GEE code
Paste the following complete code into the Google Earth Engine Code Editor and click Run. A direct download link will appear on the map panel and in the Console.
/************************************************************
FINAL CLEAN GEE CODE
For each GLOF row:
1. Extract climate of exact event year-month
2. Extract slope at exact DEM pixel
3. Generate direct CSV download link
Climate dataset:
ECMWF/ERA5_LAND/MONTHLY_AGGR
Terrain dataset for slope:
COPERNICUS/DEM/GLO30
Important:
GEE coordinate order = [Longitude, Latitude]
************************************************************/
// ---------------------------------------------------------
// 1. SETTINGS
// ---------------------------------------------------------
var climateScale = 11132; // ERA5-Land approximate spatial resolution
var terrainScale = 30; // Copernicus DEM GLO-30 approximate spatial resolution
// ---------------------------------------------------------
// 2. INPUT DATA
// Format:
// [ID, Glacier/Lake Name, Year, Month, Day, Longitude, Latitude]
// ---------------------------------------------------------
var inputData = [
[1, 'Nae', 1977, 9, '3', 86.84, 27.83],
[2, 'Nagma Pokhari Phuchan', 1980, 6, '23', 87.87, 27.87],
[3, 'Langmoche', 1985, 8, '4', 86.59, 27.87],
[4, 'Chubung Ripimo Shar', 1991, 7, '12', 86.47, 27.89],
[5, 'Sabai', 1998, 9, '3', 86.85, 27.74],
[6, 'Halji', 2004, 6, 'NA', 81.48, 30.27],
[7, 'Halji', 2006, 6, 'NA', 81.48, 30.27],
[8, 'Halji', 2007, 6, 'NA', 81.48, 30.27],
[9, 'Halji', 2008, 6, 'NA', 81.48, 30.27],
[10, 'Halji', 2009, 6, '23', 81.48, 30.27],
[11, 'Halji', 2011, 6, '30', 81.48, 30.27],
[12, 'Langmoche', 2015, 4, '25', 86.59, 27.87],
[13, 'Lhotse', 2015, 5, '25', 86.89, 27.91],
[14, 'Lhotse', 2016, 6, '12', 86.89, 27.91],
[15, 'Changri Shar', 2017, 7, '15', 86.82, 27.98],
[16, 'Barun', 2017, 4, '20', 87.14, 27.81],
[17, 'Pemdang Pokhari', 2021, 6, '14', 85.52, 28.13],
[18, 'Birendra Taal', 2024, 4, '21', 84.63, 28.60],
[19, 'Thyangbo', 2024, 8, '16', 86.57, 27.83],
[20, 'Til', 2025, 5, '15', 81.45, 30.24],
[21, 'Unnamed', 2025, 7, '8', 83.82, 29.29]
];
// ---------------------------------------------------------
// 3. CONVERT INPUT DATA TO FEATURE COLLECTION
// ---------------------------------------------------------
var points = ee.FeatureCollection(inputData.map(function(row) {
var id = row[0];
var name = row[1];
var year = row[2];
var month = row[3];
var day = row[4];
var lon = row[5];
var lat = row[6];
return ee.Feature(ee.Geometry.Point([lon, lat]), {
'Point_ID': id,
'Glacier_Lake_Name': name,
'Event_Year': year,
'Event_Month': month,
'Event_Day': day,
'Event_Date_Text': year + '/' + month + '/' + day,
'Longitude': lon,
'Latitude': lat
});
}));
Map.centerObject(points, 6);
Map.addLayer(points, {color: 'red'}, 'GLOF Points');
print('Input Points:', points);
// ---------------------------------------------------------
// 4. TERRAIN DATA FOR SLOPE
// ---------------------------------------------------------
// DEM:
// Copernicus DEM GLO-30, static DSM, approx. 30 m
//
// Slope:
// Calculated from DEM using ee.Terrain.slope()
// Unit = degree
// ---------------------------------------------------------
var demCollection = ee.ImageCollection('COPERNICUS/DEM/GLO30')
.select('DEM');
// Keep native DEM projection before slope calculation.
var demProjection = ee.Image(demCollection.first()).projection();
var dem = demCollection
.mosaic()
.rename('DEM_for_slope')
.setDefaultProjection(demProjection);
var slopeDegree = ee.Terrain.slope(dem)
.rename('Slope_degree');
var slopePercent = slopeDegree
.multiply(Math.PI)
.divide(180)
.tan()
.multiply(100)
.rename('Slope_percent');
var terrainImage = ee.Image.cat([
slopeDegree,
slopePercent
]);
Map.addLayer(slopeDegree, {min: 0, max: 60}, 'Slope Degree');
// ---------------------------------------------------------
// 5. EXTRACT EVENT YEAR-MONTH CLIMATE + SLOPE
// ---------------------------------------------------------
var extracted = points.map(function(f) {
var eventYear = ee.Number(f.get('Event_Year'));
var eventMonth = ee.Number(f.get('Event_Month'));
var monthStart = ee.Date.fromYMD(eventYear, eventMonth, 1);
var monthEnd = monthStart.advance(1, 'month');
var daysInMonth = monthEnd.difference(monthStart, 'day');
// ERA5-Land monthly image for exact event year-month.
var era5Month = ee.ImageCollection('ECMWF/ERA5_LAND/MONTHLY_AGGR')
.filterDate(monthStart, monthEnd)
.select([
'total_precipitation_sum',
'temperature_2m',
'surface_pressure'
])
.first();
era5Month = ee.Image(era5Month);
// Rainfall:
// ERA5 monthly precipitation = accumulated rainfall of that month in meters.
// Convert m/month to mm/month.
var monthlyRainfallMM = era5Month.select('total_precipitation_sum')
.multiply(1000)
.rename('Monthly_Rainfall_Event_Month_mm');
// Mean daily rainfall during the event month.
var meanDailyRainfallMM = monthlyRainfallMM
.divide(ee.Image.constant(daysInMonth))
.rename('Mean_Daily_Rainfall_Event_Month_mm_per_day');
// Temperature:
// ERA5 monthly temperature = monthly mean in Kelvin.
// Convert K to °C.
var temperatureC = era5Month.select('temperature_2m')
.subtract(273.15)
.rename('Mean_Monthly_Temperature_Event_Month_C');
// Surface pressure:
// ERA5 monthly pressure = monthly mean in Pascal.
// Convert Pa to hPa.
var pressureHPA = era5Month.select('surface_pressure')
.divide(100)
.rename('Mean_Monthly_Surface_Pressure_Event_Month_hPa');
var climateImage = ee.Image.cat([
monthlyRainfallMM,
meanDailyRainfallMM,
temperatureC,
pressureHPA
]);
// Extract climate at ERA5 scale.
var climateValues = climateImage.reduceRegion({
reducer: ee.Reducer.first(),
geometry: f.geometry(),
scale: climateScale,
maxPixels: 1e8,
tileScale: 4
});
// Extract slope at exact DEM pixel.
var terrainValues = terrainImage.reduceRegion({
reducer: ee.Reducer.first(),
geometry: f.geometry(),
scale: terrainScale,
maxPixels: 1e8,
tileScale: 4
});
return f
.set(climateValues)
.set(terrainValues)
.set({
'Climate_Type': 'Exact event year-month',
'Climate_Month_Start': monthStart.format('YYYY-MM-dd'),
'Climate_Month_End_Exclusive': monthEnd.format('YYYY-MM-dd'),
'Days_In_Event_Month': daysInMonth,
'Climate_Dataset': 'ECMWF ERA5-Land Monthly Aggregated',
'Slope_DEM_Dataset': 'Copernicus DEM GLO-30',
'DEM_Type': 'Static DSM',
'DEM_Reference_Period': 'Approx. 2011-2015',
'DEM_Spatial_Resolution': 'Approx. 30 m',
'Rainfall_Note': 'Monthly rainfall is accumulated rainfall of the exact event month.',
'Slope_Note': 'Slope is calculated from Copernicus DEM GLO-30 and extracted at the exact DEM pixel of the coordinate.'
});
});
extracted = extracted.sort('Point_ID');
print('FINAL EXTRACTED TABLE:', extracted);
// ---------------------------------------------------------
// 6. CSV OUTPUT COLUMNS
// ---------------------------------------------------------
var selectors = [
'Point_ID',
'Glacier_Lake_Name',
'Event_Date_Text',
'Event_Year',
'Event_Month',
'Event_Day',
'Longitude',
'Latitude',
'Climate_Type',
'Climate_Month_Start',
'Climate_Month_End_Exclusive',
'Days_In_Event_Month',
'Monthly_Rainfall_Event_Month_mm',
'Mean_Daily_Rainfall_Event_Month_mm_per_day',
'Mean_Monthly_Temperature_Event_Month_C',
'Mean_Monthly_Surface_Pressure_Event_Month_hPa',
'Slope_degree',
'Slope_percent',
'Climate_Dataset',
'Slope_DEM_Dataset',
'DEM_Type',
'DEM_Reference_Period',
'DEM_Spatial_Resolution',
'Rainfall_Note',
'Slope_Note'
];
// ---------------------------------------------------------
// 7. DIRECT CSV DOWNLOAD LINK
// ---------------------------------------------------------
var csvUrl = extracted.getDownloadURL({
format: 'CSV',
filename: 'GLOF_Nepal_EventMonth_Climate_Slope_Clean',
selectors: selectors
});
print('DIRECT CSV DOWNLOAD URL:', csvUrl);
// ---------------------------------------------------------
// 8. MAP DOWNLOAD PANEL
// ---------------------------------------------------------
var panel = ui.Panel({
style: {
position: 'top-left',
padding: '8px',
width: '390px'
}
});
panel.add(ui.Label({
value: 'GLOF Climate + Slope CSV',
style: {
fontWeight: 'bold',
fontSize: '16px'
}
}));
panel.add(ui.Label(
'Climate = exact event year-month. Slope = exact DEM pixel.'
));
panel.add(ui.Label({
value: 'Download CSV Directly',
targetUrl: csvUrl,
style: {
color: 'blue',
textDecoration: 'underline',
fontSize: '14px',
fontWeight: 'bold'
}
}));
Map.add(panel);
// ---------------------------------------------------------
// 9. SIMPLE CHECK CHARTS
// ---------------------------------------------------------
function makeColumnChart(propertyName, titleText, yAxisText) {
var chart = ui.Chart.feature.byFeature({
features: extracted,
xProperty: 'Point_ID',
yProperties: [propertyName]
})
.setChartType('ColumnChart')
.setOptions({
title: titleText,
hAxis: {title: 'Point ID'},
vAxis: {title: yAxisText},
legend: {position: 'none'}
});
print(chart);
}
makeColumnChart(
'Monthly_Rainfall_Event_Month_mm',
'Monthly Rainfall of Event Month',
'Rainfall, mm/month'
);
makeColumnChart(
'Mean_Monthly_Temperature_Event_Month_C',
'Mean Monthly Temperature of Event Month',
'Temperature, °C'
);
makeColumnChart(
'Mean_Monthly_Surface_Pressure_Event_Month_hPa',
'Mean Monthly Surface Pressure of Event Month',
'Pressure, hPa'
);
makeColumnChart(
'Slope_degree',
'Slope at Exact DEM Pixel',
'Slope, degree'
);
Recommended methodology wording
Event-month climate variables were extracted from the ERA5-Land Monthly Aggregated dataset in Google Earth Engine. For each GLOF location, the event year and month were used to select the corresponding monthly ERA5-Land image. Monthly rainfall represents accumulated precipitation for the event month, while mean monthly temperature and mean monthly surface pressure were obtained from ERA5-Land monthly mean bands after unit conversion. Slope was derived from the Copernicus DEM GLO-30 dataset using the Google Earth Engineee.Terrain.slope()function and sampled at each coordinate. Elevation is not exported as a separate CSV variable in this version; the DEM is loaded only as the source surface for slope calculation. The final point-based table was downloaded directly as a CSV usingFeatureCollection.getDownloadURL().
[longitude, latitude], not [latitude, longitude].