DeepSeek is a free AI chatbot (deepseek.com) that writes excellent Google Earth Engine JavaScript code. Unlike APIs, you simply ask in natural language, copy the code, and paste it into GEE. No authentication, no API keys, no cost.
This course teaches you how to write effective prompts for flood mapping using Sentinel-1 SAR (cloud-penetrating radar). By the end, you'll generate your own custom flood scripts.
1. Open chat.deepseek.com (create free account if needed).
2. Open code.earthengine.google.com in another tab.
3. Create a new script: Course03_Flood_DeepSeek.
Optical sensors (Sentinel-2) can't see through clouds. For flood emergencies, we use Sentinel-1 C-band SAR (radar). Water surfaces appear dark (smooth, specular reflection) while land is brighter.
| Parameter | Value |
|---|---|
| Sensor | Sentinel-1 A/B (C-band SAR, 5.405 GHz) |
| Resolution | 10m (GRD) |
| Polarization | VV, VH (VV best for water detection) |
| Key pre-processing | Thermal noise removal, radiometric calibration, terrain correction (SRTM), speckle filter |
The standard method: difference between pre-flood and during-flood VV backscatter. Flooded areas show a sharp decrease in backscatter (darkening).
To get working GEE code, your prompt must be specific, include dataset IDs, region, dates, and desired output.
You can adapt the coordinates and dates to any flood event worldwide.
floodMask = diff.gt(2))ee.Image.pixelArea()If the output is incomplete, ask DeepSeek: "Continue the code" or "Add a legend panel".
1. In GEE code editor, delete any existing code.
2. Paste the DeepSeek-generated script.
3. Click Run. Inspect the Console for area printed. Check the Map for flood extent layer.
4. If errors appear (e.g., collection empty, wrong filter), ask DeepSeek to fix: "The code gives error 'ImageCollection.select: band VV not found'. Please correct the band name to 'VV'."
After running the generated code, you will see:
Map.addLayer(floodMask.selfMask(),
{palette: ['#1E88E5'], min: 1, max: 1},
'Flood Extent (Thresholded)');Adjust the threshold (e.g., 1.5 dB or 2.5 dB) by modifying the .gt(2) value in the script. Higher threshold reduces false positives.
The generated code will compute flooded area in hectares using ee.Image.pixelArea() and a reducer.
var floodArea = floodMask.selfMask()
.multiply(ee.Image.pixelArea())
.reduceRegion({
reducer: ee.Reducer.sum(),
geometry: studyArea,
scale: 10,
maxPixels: 1e9
});
var areaHa = ee.Number(floodArea.get('floodMask')).divide(10000);
print('Flooded area (ha):', areaHa);You can ask DeepSeek: "Modify the script to compute weekly flood progression for March 2024" to get a time-series animation.
DeepSeek will usually include an export block. If not, ask: "Add an Export.image.toDrive for the flood mask."
Export.image.toDrive({
image: floodMask.selfMask().rename('flood_extent'),
description: 'Flood_Map_Sentinel1',
folder: 'GEE_Floods',
region: studyArea,
scale: 10,
crs: 'EPSG:4326',
maxPixels: 1e9
});ui.Chart.image.series.// =============================================
// Flood Mapping with Sentinel-1 SAR
// Generated by DeepSeek AI (March 2026)
// Study area: Martil, Tetouan, Morocco (adjustable)
// =============================================
// ---- 1. Define study area (rectangle) ----
var studyArea = ee.Geometry.Rectangle([-5.32, 35.58, -5.22, 35.66]);
Map.setCenter(-5.27, 35.62, 12);
Map.addLayer(studyArea, {color: 'red'}, 'Study Area', false);
// ---- 2. Sentinel-1 pre-processing functions ----
function maskEdges(image) {
return image.updateMask(image.select('VV').gte(-30));
}
function applySpeckleFilter(image) {
// Simple Lee filter using focal_mean (approximation)
var smoothed = image.select('VV').focal_mean(3, 'circle', 'meters');
return image.addBands(smoothed.rename('VV_smoothed'), null, true);
}
// ---- 3. Load Sentinel-1 GRD (VV, IW, ascending/descending) ----
var s1 = ee.ImageCollection('COPERNICUS/S1_GRD')
.filterBounds(studyArea)
.filter(ee.Filter.listContains('transmitterReceiverPolarisation', 'VV'))
.filter(ee.Filter.eq('instrumentMode', 'IW'))
.filter(ee.Filter.or(
ee.Filter.eq('orbitProperties_pass', 'ASCENDING'),
ee.Filter.eq('orbitProperties_pass', 'DESCENDING')
))
.map(function(img) {
return img.select('VV');
})
.map(maskEdges)
.map(applySpeckleFilter)
.map(function(img) {
// Convert to dB
return img.addBands(img.select('VV_smoothed').log10().multiply(10).rename('VV_dB'));
});
// ---- 4. Define pre-flood and flood periods ----
var preStart = '2024-01-01';
var preEnd = '2024-02-28';
var floodStart = '2024-12-10';
var floodEnd = '2024-12-20';
var preFloodCol = s1.filterDate(preStart, preEnd);
var floodCol = s1.filterDate(floodStart, floodEnd);
// Check if collections have images
print('Pre-flood images count:', preFloodCol.size());
print('Flood images count:', floodCol.size());
// Compute mean backscatter (dB)
var preMean = preFloodCol.select('VV_dB').mean().rename('pre_dB');
var floodMean = floodCol.select('VV_dB').mean().rename('flood_dB');
// ---- 5. Compute difference and threshold ----
var diff = preMean.subtract(floodMean).rename('diff_db');
// Flooded areas show decrease > 2 dB (water darker)
var floodMask = diff.gt(2).rename('flood_mask');
// ---- 6. Visualisation ----
var dbVis = {min: -25, max: 0, palette: ['black', 'gray', 'white']};
Map.addLayer(preMean.clip(studyArea), dbVis, 'Pre-flood VV (dB)');
Map.addLayer(floodMean.clip(studyArea), dbVis, 'Flood VV (dB)');
Map.addLayer(diff.clip(studyArea), {min: -5, max: 5, palette: ['blue', 'white', 'red']}, 'Difference (pre - flood)');
Map.addLayer(floodMask.selfMask().clip(studyArea), {palette: ['#1E88E5']}, 'Flood Extent (threshold >2 dB)');
// ---- 7. Compute flooded area (hectares) ----
var floodAreaImg = floodMask.selfMask().multiply(ee.Image.pixelArea());
var areaStats = floodAreaImg.reduceRegion({
reducer: ee.Reducer.sum(),
geometry: studyArea,
scale: 10,
maxPixels: 1e9
});
var floodedHa = ee.Number(areaStats.get('flood_mask')).divide(10000);
print('Flooded area (ha):', floodedHa);
// ---- 8. Legend ----
var legend = ui.Panel({
style: {position: 'bottom-left', padding: '10px'}
});
legend.add(ui.Label('Flood Extent Legend', {fontWeight: 'bold', margin: '0 0 4px 0'}));
var colorPanel = ui.Panel({layout: ui.Panel.Layout.Flow('horizontal')});
colorPanel.add(ui.Label({style: {backgroundColor: '#1E88E5', padding: '8px', margin: '0 4px 0 0'}}));
colorPanel.add(ui.Label('Flooded area (dB drop >2)'));
legend.add(colorPanel);
Map.add(legend);
// ---- 9. Click inspector for backscatter values ----
var inspector = ui.Panel({style: {position: 'top-right', width: '250px', padding: '8px'}});
inspector.add(ui.Label('Click Inspector', {fontWeight: 'bold'}));
var infoLabel = ui.Label('Click on map');
inspector.add(infoLabel);
Map.add(inspector);
Map.onClick(function(coords) {
var point = ee.Geometry.Point([coords.lon, coords.lat]);
var values = diff.addBands(floodMask).reduceRegion({
reducer: ee.Reducer.first(),
geometry: point,
scale: 10
});
values.evaluate(function(vals) {
var diffVal = vals.diff_db;
var flooded = vals.flood_mask;
infoLabel.setValue('Diff: ' + (diffVal ? diffVal.toFixed(2) : 'N/A') + ' dB | Flooded: ' + (flooded === 1 ? 'Yes' : 'No'));
});
});
// ---- 10. Export flood mask ----
Export.image.toDrive({
image: floodMask.selfMask().rename('flood_extent'),
description: 'Flood_Map_Sentinel1_Martil',
folder: 'GEE_Floods',
region: studyArea,
scale: 10,
crs: 'EPSG:4326',
maxPixels: 1e9
});.filterDate('2024-11-01','2024-11-15') for a known flood event.To get the best results from DeepSeek for GEE tasks:
'COPERNICUS/S2_SR_HARMONIZED' or 'GOOGLE/DYNAMICWORLD/V1'.