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.

Final output: monthly rainfall of the exact event month, mean daily rainfall in that month, mean monthly temperature, mean monthly surface pressure, slope in degrees, and slope percent for each coordinate.

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/GLO30
ee.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
Note: The final CSV does not export elevation as a separate variable in this version. However, Copernicus DEM GLO-30 is still loaded because slope is calculated from the DEM.

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
Key point: Per-day calculation is done only for rainfall. Temperature and surface pressure are directly adopted from the ERA5-Land monthly mean bands, with only unit conversion applied.

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 Engine ee.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 using FeatureCollection.getDownloadURL().
Data-quality reminder: Always verify that your coordinate order is correct. Google Earth Engine uses [longitude, latitude], not [latitude, longitude].