Number of dry and wet-spell

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

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

Previous
Previous

Kriging and IDW interpolation in GEE

Next
Next

Calculate SPI using CHIRPS data