Benny Istanto Logo Benny Istanto Logo
  • Home
  • About
  • CSR
  • Blog
    • All Posts
    • Archive by Year
  • Works
    • Overview
    • Experiences
    • Projects
    • Consulting
    • Maps & Infographics
  • CV

Number of dry and wet-spell

Remote Sensing
Research
Climate
Now, it’s easy to get statistics information on AVERAGE, MINIMUM and MAXIMUM number of consecutive dry and wet days for a certain period using Google Earth Engine platform
Author

Benny Istanto

Published

July 21, 2020

Now, it’s easy to get statistics information on AVERAGE, MINIMUM and MAXIMUM number of consecutive dry and wet days for a certain period using Google Earth Engine platform. Copy below code and paste into GEE.

You can modify:

  • Bounding box or area of interest
  • Start and End of YEAR, MONTH and DATE
  • Precipitation threshold which can be considered as rain day.
  • Symbology as SLD style
  • Palette
NoteJavascript - GEE Dry-Wet days
// BBox for Indonesia
var rectangle = ee.Geometry.Rectangle(92.126, -13.242, 145.3, 8.405); //Indonesia
var bbox_Indonesia = ee.Feature(rectangle).geometry();
Map.setCenter(120, -2, 5);

// Import CHIRPS Daily
var CHIRPS = ee.ImageCollection("UCSB-CHG/CHIRPS/DAILY");

// Define time range
var startyear = 1981;
var endyear = 2019;
var startmonth = 7; // Set for July
var endmonth = 7; // Set for July

// Set EE date format
var startdate = ee.Date.fromYMD(startyear,startmonth,1);
var enddate = ee.Date.fromYMD(endyear,endmonth,31);

// Filter data
var datain_t = CHIRPS.filterDate(startdate, enddate)
  .filter(ee.Filter.calendarRange(startmonth,endmonth, 'month'))
  .select("precipitation").map(function(img){
    return img.addBands(ee.Image.constant(0).uint8().rename('counter'));
  })
  .sort('system:time_start');

// Start reading the data 
var dataset = datain_t
.filterDate(startdate,enddate)
.sort('system:time_start:');
print(dataset,"dataset");

var precipThresh = 1; // mm

function wetSpells(imgWS, listWS){
  // get previous image
  var prevWS = ee.Image(ee.List(listWS).get(-1));
  // find areas gt precipitation threshold (gt==0, lt==1) 
  var wet = imgWS.select('precipitation').gt(precipThresh);
  // add previous day counter to today's counter
  var accumWS = prevWS.select('counter').add(wet).rename('counter');
  // create a result image for iteration
  // precip < thresh will equall the accumulation of counters
  // otherwise it will equal zero
  var outWS = imgWS.select('precipitation').addBands(
        imgWS.select('counter').where(wet.eq(1),accumWS)
      ).uint8();
  return ee.List(listWS).add(outWS);
}

function drySpells(imgDS, listDS){
  // get previous image
  var prevDS = ee.Image(ee.List(listDS).get(-1));
  // find areas gt precipitation threshold (gt==0, lt==1) 
  var dry = imgDS.select('precipitation').lt(precipThresh);
  // add previous day counter to today's counter
  var accumDS = prevDS.select('counter').add(dry).rename('counter');
  // create a result image for iteration
  // precip < thresh will equall the accumulation of counters
  // otherwise it will equal zero
  var outDS = imgDS.select('precipitation').addBands(
        imgDS.select('counter').where(dry.eq(1),accumDS)
      ).uint8();
  return ee.List(listDS).add(outDS);
}

// Create first image for iteration
var first = ee.List([ee.Image(dataset.first())]);


// apply wet spell iteration function
var maxWetSpell = ee.ImageCollection.fromImages(
    dataset.iterate(wetSpells,first)
).max(); // get the max value

var minWetSpell = ee.ImageCollection.fromImages(
    dataset.iterate(wetSpells,first)
).min(); // get the min value

var meanWetSpell = ee.ImageCollection.fromImages(
    dataset.iterate(wetSpells,first)
).mean(); // get the mean value


// apply dry spell iteration function
var maxDrySpell = ee.ImageCollection.fromImages(
    dataset.iterate(drySpells,first)
).max(); // get the max value

var minDrySpell = ee.ImageCollection.fromImages(
    dataset.iterate(drySpells,first)
).min(); // get the min value

var meanDrySpell = ee.ImageCollection.fromImages(
    dataset.iterate(drySpells,first)
).mean(); // get the mean value


// Define an SLD style of discrete intervals to apply to the image.
var wetSpellsSLD =
  '<RasterSymbolizer>' +
    '<ColorMap  type="intervals" extended="false" >' +
      '<ColorMapEntry color="#cccccc" quantity="0" label="No Rain"/>' +
      '<ColorMapEntry color="#ffffcc" quantity="5" label="1-5" />' +
      '<ColorMapEntry color="#c6e8b3" quantity="10" label="6-10" />' +
      '<ColorMapEntry color="#7eccba" quantity="20" label="11-20" />' +
      '<ColorMapEntry color="#41b7c4" quantity="30" label="21-30" />' +
      '<ColorMapEntry color="#2c80b8" quantity="60" label="31-60" />' +
      '<ColorMapEntry color="#253494" quantity="1000" label=">61" />' +
    '</ColorMap>' +
  '</RasterSymbolizer>';


// Define an SLD style of discrete intervals to apply to the image.
var drySpellsSLD =
  '<RasterSymbolizer>' +
    '<ColorMap  type="intervals" extended="false" >' +
      '<ColorMapEntry color="#cccccc" quantity="0" label="No Drought"/>' +
      '<ColorMapEntry color="#ffe5d9" quantity="5" label="1-5" />' +
      '<ColorMapEntry color="#fcbba2" quantity="10" label="6-10" />' +
      '<ColorMapEntry color="#fc9172" quantity="20" label="11-20" />' +
      '<ColorMapEntry color="#fa6949" quantity="30" label="21-30" />' +
      '<ColorMapEntry color="#de2c26" quantity="60" label="31-60" />' +
      '<ColorMapEntry color="#a60e13" quantity="1000" label=">61" />' +
    '</ColorMap>' +
  '</RasterSymbolizer>';  

// Display results
Map.addLayer(meanWetSpell.select('counter').sldStyle(wetSpellsSLD).clip(bbox_Indonesia), {},'Avg Wet Spells', false);
Map.addLayer(minWetSpell.select('counter').sldStyle(wetSpellsSLD).clip(bbox_Indonesia), {},'Min Wet Spells', false);
Map.addLayer(maxWetSpell.select('counter').sldStyle(wetSpellsSLD).clip(bbox_Indonesia), {},'Max Wet Spells', true);
Map.addLayer(meanDrySpell.select('counter').sldStyle(drySpellsSLD).clip(bbox_Indonesia), {},'Avg Dry Spells', false);
Map.addLayer(minDrySpell.select('counter').sldStyle(drySpellsSLD).clip(bbox_Indonesia), {},'Min Dry Spells', false);
Map.addLayer(maxDrySpell.select('counter').sldStyle(drySpellsSLD).clip(bbox_Indonesia), {},'Max Dry Spells', true);


// Export the result to Google Drive
Export.image.toDrive({
  image:maxDrySpell,
  description:'MaxWetSpell_07_July',
  folder:'GEE',
  scale:maxDrySpell.projection().nominalScale(),
  region: bbox_Indonesia,
  maxPixels:1e12
});


// Legend
// Set position of panel
var legend = ui.Panel({
  style: {
    position: 'bottom-left',
    padding: '8px 15px'
  }
});
 
// Create legend title
var legendTitle = ui.Label({
//  value: 'Dry-spells',
  value: 'Wet-spells',
  style: {
    fontWeight: 'bold',
    fontSize: '14px',
    margin: '0 0 4px 0',
    padding: '0'
    }
});
 
// Add the title to the panel
legend.add(legendTitle);
 
// Creates and styles 1 row of the legend.
var makeRow = function(color, name) {
 
      // Create the label that is actually the colored box.
      var colorBox = ui.Label({
        style: {
          backgroundColor: '#' + color,
          // Use padding to give the box height and width.
          padding: '8px',
          margin: '0 0 4px 0'
        }
      });
 
      // Create the label filled with the description text.
      var description = ui.Label({
        value: name,
        style: {margin: '0 0 4px 6px'}
      });
 
      // return the panel
      return ui.Panel({
        widgets: [colorBox, description],
        layout: ui.Panel.Layout.Flow('horizontal')
      });
};
 
// Palette with the colors
// var palette =['cccccc','ffe5d9','fcbba2','fc9172','fa6949','de2c26','a60e13']; // Dry
var palette =['cccccc','ffffcc','c6e8b3','7eccba','41b7c4','2c80b8','253494']; // Wet


// Name of the legend
// var names = ['No Drought','1 - 5 days','6 - 10 days','11 - 20 days','21 - 30 days','31 - 60 days','> 60 days'];
var names = ['No Rain','1 - 5 days','6 - 10 days','11 - 20 days','21 - 30 days','31 - 60 days','> 60 days'];

// Add color and and names
for (var i = 0; i < 7; i++) {
  legend.add(makeRow(palette[i], names[i]));
  }  
 
// Add legend to map 
Map.add(legend);

// End of script

Example of the analysis

Link for the full code

Notes: The code was compiled from various source (GEE help, GEE Groups, StackExchange)

Back to top
PreviousCalculate SPI using CHIRPS data NextKriging and IDW interpolation in GEE

© 2026, Benny Istanto.

Exploring Climate with GIS and Data Science, solving old problems in new ways. Turning earth observation data into actionable, life-saving insights.

Built with Quarto

Privacy

All content on this website does not represent the views of my (current or previous) employer.

  • View source
  • Report an issue

Buy Me a Coffee