Working with Gridded Rainfall Data in Google Earth Engine

Many useful climate and weather datasets come as gridded rasters. The techniques for working with them is slightly different than other remote sensing datasets. In this post, I will show how to work with gridded rainfall data in Google Earth Engine. This post also serves an an example of how to use the map/reduce programming style to efficiently work with such large datasets.

We will use CHIRPS (Climate Hazards Group InfraRed Precipitation with Station) Data in this tutorial. This is a high-resolution global gridded rainfall dataset that combines satellite measured precipitation with ground station data in a consistent long time-series dataset. This data is available from 1981 onwards and is extremely useful in computing rainfall deviation and drought monitoring. See this paper for more discussion on applying CHIRPS dataset for calculating trends and variability, including Earth Engine code for pixel-wise trends and statistical significance. (code links under Supplementary Materials)

Earth Engine Data Catalog includes many other gridded precipitation datasets, such as ERA5 and GPM – each with different spatial and temporal resolutions and methodologies. The technique for working with them is identical to the one outlined in this post.

We will take this data and learn how to tackle the following problems

  • Create a map of total rainfall in a given time-period.
  • Calculate the total annual rainfall in an administrative region or a polygon.
  • Create a CSV file of total annual rainfall for any given region for the past 40 years.

Access the Data

The primary computing time step for the CHIRP is the pentad. Pentad represents the grouping of 5 days. There are 6 pentads in a calendar month: Five 5-day pentads and One pentad with the remaining 3 to 6 days of the month. Pentads reset at the beginning of each month. We will use the CHIRPS pentad dataset. Note that CHIRPS is also provided in a daily time-step which is computed by disaggregating the pentad data. Unless you specifically need daily data, you should use the pentad dataset.

var chirps = ee.ImageCollection('UCSB-CHG/CHIRPS/PENTAD')

Creating a Map of Total Rainfall

Let’s create a map of total annual rainfall. The CHIRPS dataset is an ImageCollection with a global image consisting of an Image for every pentad (5 days) with total rainfall in during those 5 days. We can filter the collection to images for a year and then apply a sum() reducer to get a single image where each pixel is the sum of rainfall from all images in the year. The following code computes the total rainfall for the year 2017

var year = 2017
var startDate = ee.Date.fromYMD(year, 1, 1)
var endDate = startDate.advance(1, 'year')
var filtered = chirps
  .filter(ee.Filter.date(startDate, endDate))
var total = filtered.reduce(ee.Reducer.sum())

Remember – the result of applying a reducer to an ImageCollection is an Image. So now that we have an image, we can visualize it to get our map of annual rainfall. The unit of CHIRPS data is millimeters (mm), so 2000 mm/year is a reasonable max value for visualization.

Tip: If you want cartographer-approved color ramps and palettes for your maps, head over to ColorBrewer. The palette from the map below is created using this excellent free resource.

var palette = ['#ffffcc','#a1dab4','#41b6c4','#2c7fb8','#253494']
var visParams = {
  min:0,
  max: 2000,
  palette: palette
}
Map.addLayer(total, visParams, 'Total Precipitation')

Calculating Total Rainfall in a Region

Most hydrological applications will require computing the Areal Mean Rainfall (AMR) – which is the average total rainfall in a region. The region could be anything – a river basin, an administrative area (city/district) or a polygon. Now that we have computed an Image with the total rainfall for each pixel, we can compute average total rainfall in any given geometry using reduceRegion() function. For this example, we will compute the total average rainfall within the city of Bengaluru, India. In the code below, we specify 5000m as the scale. CHIRPS spatial resolution is 0.05° – which is approximately 6km. The result of a reduceRegion() operation is a dictionary which has the stats for each band of the image. Since CHIRPS data has only 1 band named precipitation, the dictionary will have only a single key named precipitation_sum.

bangalore = ee.FeatureCollection("users/ujavalgandhi/public/bangalore_boundary");
var stats = total.reduceRegion({
  reducer: ee.Reducer.mean(),
  geometry: bangalore,
  scale: 5000,
  })
print(stats.get('precipitation_sum')) // 1336.52 mm

We can clip the image with the region geometry and display the results.

// Clip the image to the city boundary and display
var totalBangalore = total.clip(bangalore)
Map.addLayer(totalBangalore, visParams, 'Total Precipitation (Bangalore)')

Calculating a Time Series of Rainfall

The biggest advantage of the CHIRPS dataset is the long and consistent time series it provides. Combined with the parallel-processing power of Earth Engine, it enables us to get statistics over long periods of time very easily. Here’s where the map() operation comes handy. Data processing in Earth Engine boils down to a) create a list or collection and b) mapping a function over it and optionally c) reducing the results. Here we will write a function that calculates total rainfall for a region for 1 year, and then map() that function over a list of 40 years. map() allows each operation to run in parallel and you will see that a large computation like this finishes in just a few seconds.

Tip: In Earth Engine, if the result of your computation is a number, list or a dictionary – always return them as Features. FeatureCollections allow filters, export and many more operations that other data structures do not allow. It is easy to create a feature with a null geometry as shown below.

// Function to calculate rainfall for 1 year
var yearlyRainfall = function(year) {
  var startDate = ee.Date.fromYMD(year, 1, 1)
  var endDate = startDate.advance(1, 'year')
  var filtered = chirps
    .filter(ee.Filter.date(startDate, endDate))
  var total = filtered.reduce(ee.Reducer.sum())
  var stats = total.reduceRegion({
    reducer: ee.Reducer.mean(),
    geometry: bangalore,
    scale: 5000,
  })
  var f = ee.Feature(null, {
    'year': year,
    'precipitation': stats.get('precipitation_sum')
  })
  return f
}

Now that we have a function that can calculate total rainfall for 1 year, we can map() it over a list of years to get rainfall for ALL years.

var years = ee.List.sequence(1981, 2019)
var rainfallYears = ee.FeatureCollection(
  years.map(yearlyRainfall))

That’s it. rainfallYears is a FeatureCollection with total rainfall for each year. We can export it to get the data as a CSV file.

Export.table.toDrive({
  collection: rainfallYears,
  folder: 'earthengine',
  fileNamePrefix: 'rainfallbyyear',
  fileFormat: 'CSV'}) 

You can see the full script with comments at https://code.earthengine.google.co.in/ce12cf04015633e195e502d7efb3b942

If you are curious, this is what the exported CSV looks like. Past 39 years of total rainfall in Bangalore city as calculated from the CHIRPS dataset.

If you are new to Earth Engine and want to master it, check out my course End-to-End Google Earth Engine.

YearRainfall (mm)
1981992
1982570
1983905
1984758
1985717
1986981
1987794
19881114
1989833
1990756
19911030
1992739
1993841
1994763
19951052
19961108
1997739
19981378
19991084
20001085
20011133
2002727
2003751
20041108
20051414
2006818
20071280
20081144
20091034
20101378
20111093
2012873
2013998
20141030
20151100
2016663
20171337
2018923
20191036

110 Comments

Leave a Comment

  1. Very good job your investigation. Have you tried the ERA5 Monthly aggregates – Latest climate reanalysis produced by ECMWF / Copernicus Climate Change Service catalog?

    • I haven’t worked with ERA5 data. ERA5 is 0.25-degree resolution which is much coarser than CHIRPS. There is also GPM available in Earth Engine. Seems like I need another post comparing all precipitation data sources 🙂

      • Thanks for this detailed post! Have you already written a post regarding the comparison of different precipitation data sources, if so, could you kindly send the link.

      • There are many research papers on this topic. But the comparison really depends on the country/region and application (absolute measurements vs trend analysis). So hard to come up with a general recommendation.

  2. how can we estimate rainfall for particular date with 30 minutes time interval using GPM.. at every 30 minute there should be 1 output in tiff format.

    • You are asking 2 different questions
      1. GPM data comes as 1 image every 3 hours. If you want to download GPM data as GeoTiff, you can just download it from the source from https://gpm.nasa.gov/data/directory
      2. If you want to estimate rainfall in Earth Engine, you don’t need to download any data. You can just write code as described in this post to filter, map and reduce the images for your region and you will get a CSV output. The code is fairly straightforward and this post guides on how one might approach it. If you want to do this and you are new to Earth Engine, you’ll have to learn how to write code and understand how the system works. You can complete various tutorials to start learning https://developers.google.com/earth-engine/tutorials/tutorials

  3. Thank you very much for this post. I am very new to GEE. I need 10 day total rainfall composite. Should I use Pentad or CHIRPS daily? Can I use the same code for CHIRPS daily?

    • If you want 10-day composites starting at beginning of each month, then you can use Pentad. If you want a 10-day composite starting from any date, it is better to use the CHIRPS daily data. Same code would work, just replace the pentad collection with daily. I explain pentad vs daily in detail in this video https://youtu.be/zHUCM3XLc6k?t=122

      • Thank you for the reply. Your videos are excellent like your blog.
        Should I use .advance(‘day’) instead of year because I want 10 day totals? In many code on stackexchange for daily collections, first a date list is created, then mapped over it and the image collection is got like that. Should I also do that for 10 days collection? Because you are using .advance(‘year’). How to get 10 days totals from ‘year’ and ‘day’ ?

  4. thank you sir your blogs are awesome i did my case study on floods using your blogs help . sir in this particular example how did you clip it for bangalore as when im running for my area i cant clip it . its showing for full area

    • You can use .clip() to clip the image. Updated the post to include this code

      // Clip the image to the city boundary and display
      var totalBangalore = total.clip(bangalore)
      Map.addLayer(totalBangalore, visParams, ‘Total Precipitation (Bangalore)’)

  5. Hi, thank you very much for this guide.
    I’m trying to convert daily data to monthly and get a monthly time series for 20 years. Please guide me using this code.

  6. Hi, thank you very much for this guide.
    I’m trying to convert CHIRPS daily data to monthly and get a monthly time series for 20 years. Please guide me using this code

  7. Dear Ujaval, thank you very much for this guide. I am new in GEE. I want to say that your videos are watched even in Kyrgyzstan, Central Asia. I learn a lot by watching your videos and repeating your every step.
    I need to create Total rainfall every 16 days from 2000 to 2021 for multi polygons. I tried to use .advance(16,‘day’) instead of year. I have no result. Please help with the code.

  8. Thank you very much for your kind contribution. I am planning to get monthly and annually mean values of precipitation for several years, instead of the total value. Also, I would like to use NEX-GDPP dataset. Could you please kindly guide me if it’s possible?

  9. Thank you.

    I am using GPM: Monthly Global Precipitation Measurement (GPM) v6 and I want to calculate the annual average rainfall for one year. Could you please guide me?

  10. Thank you very much for the code. Now, how can I get the raster map of climatelogical average of 1981-2019 i.e. one raster layer.?

  11. Is it possible to get time series of daily rainfall of each coordinates available in given location ?

  12. Thank you very much sir, I was struggling for it since so many days. Thank you very much for your help.

  13. Hi, Thankyou for your post. I am trying to find the precipitation of my region. This region is actually denoted by coordnates. So, my ROI is in form of a rectangle. I tried your code for it, but showing error as ‘ComputedObject (Error), exeocted type: geometry’. Can you please help me? I am very new to GEE, and just started going through your course.

    • You need to create a geometry object from your coordinates. If you have a rectangle, use ee.Algorithms.GeometryConstructors.Rectangle() function (look in the documentation for how to use it). Once you have the geometry, the code should work. If you get an error, you have to share your code and assets to get further help.

  14. Hii ! thank you so much for your information. could you please help me for getting daily rainfall values from GPM and TRMM products with mm scale.

  15. Hello my friend, congratulations, very good your content. I have a question, I want to adapt the daily GPM script to result in the accumulated total for the day, and still, plot these values ​​on the map, how would I proceed? It would look like the product of the Giovanni/Nasa. Tks.

  16. Dear Ujaval sir,
    Thanks for the excellent guide. I am now able to do required analysis on the GEE because of your free courses.

    Sir, I want to resample the Chirps data which is 0.05 to a 0.25 degree to comapre with era-5 and persian data, will u recommend some idea ?

    Though, I have learned techniques of aggregating of pixels in population raster, I am wondering can I implement same ideas here as well?

  17. Dear sir,
    I have been following your correlation computation code.
    sir I have a two doubts to clear:
    (1) Is it necessary to have a same pixel size to calculate the correlation? (or it works like sentinel2 images calculation where bands have different saptial resolution and 20m bands works (2*2) to 10 m band.

    (2) For using all layers of era5 soil moisture, should we avaergae them ?

  18. Dear Mr. UJAVAL

    I have several points in different locations and I would like to download the rainfall data (5 months, January to May) for each point over 10 years and export it as a csv file. Can you help me as I am new to using GEE.

  19. Hi,
    I was looking for a faster way to download TRMM data at a specific location or for many locations daily rainfall data. I reviewed your site on the usage of Google Earthengine. I have used R and Python etc. This approach seems promising. Do you have code to extract at a particular lat and lon location as .CSV file?

    Thanks
    Venkat

  20. I want to plot the result on the console as a graph, the output which we export as .csv
    A bar chart showing total annual rainfall for the years. How can it be done?

  21. Also, if I wanted to apply the above code for other rainfall datasets like GSMap, GPM, ERA5, PERSIANN, what changes would needed to be done?

  22. How to get time series of weighted mean rainfall of region in the way Zonal Statistics works in Arcgis along with respective grids time series with co-ordinates detail. Below is detail of working of Zonal Statistics in Acrgis – https://pro.arcgis.com/en/pro-app/latest/tool-reference/spatial-analyst/how-zonal-statistics-works.htm Here it may also consider those grids which are out of region, but part of its rasterization covers the region. Thanks for your valuable support.

  23. Thanks for your quick response, Sir,
    I have referred both the link given by you and its only your blog where I started my learning on the subject and still it’s always helpful for me.
    Since unweighted() is giving simple mean therefore its result is not matching with result of Arcgis.
    After going through all the links mentioned at the end, my understanding is that both Arcgis and weighted mean working in GEE is same, but I am getting error in
    var areaImage = ERA5 image().addBands(AOI)
    I also tried to covert AOI into Vector(image) so that it can be added as band into ERA5. Since I am not perfect so getting error and due to which I am not able get grouped mean.
    Regarding mismatching in weighed average from GEE (without grouping or separately for each group manually) and ArcGIS is not clear since ArcGIS result is given by someone else. So, I am even not sure that whether that even is generated from ArcGIS or not and even that result is correct or not. He just told that its based-on concept mentioned in ArcGIS Article.
    Code for same is added in the link shared earlier.
    // https://medium.com/@wardarahim25/zonal-statistics-using-google-earth-engine-and-visualisation-using-python-fb74cc1b1efc
    // https://github.com/warda-rahim/articles/blob/main/gee_zonal_stats/ee_zonal_stats.ipynb
    // https://towardsdatascience.com/the-correct-way-to-average-the-globe-92ceecd172b7
    // https://phzoe.com/2022/06/23/python-netcdf-latitude-area-weighted-global-average/
    // https://developers.google.com/earth-engine/guides/reducers_weighting
    // https://developers.google.com/earth-engine/guides/reducers_grouping
    // https://pro.arcgis.com/en/pro-app/latest/tool-reference/spatial-analyst/how-zonal-statistics-works.htm

  24. Hello Ujaval sir,

    Thank you for this tutorial. I am new to GEE. I was thinking is it possible to get a plot of the total annual precipitation over the time period as a bar chart? Also, what changes should be done to the code if we are using other precipitation datasets like GPM, PERSIANN, ERA5, NEX-GDDP, GSMap instead of CHIRPS?

    Thank you.

  25. Hello. Thank you for the post.

    1. How do i calculate monthly averages across the years?
    2. Can i use this code for mapping all the states of India instead of using single city like Bangalore.

    Thanks

  26. Hello. I have an issue. I was following the guided project of rainfall deviation and was able to extract feature collection of monthly average precipitation for a period of 2 years for all states of India. I have 34 states * 12 months * 2 years = 816 features. When i try to export it as csv , i get a single column of 816 rows (as expected). Now how do i reformat it to get each column having month_year format ? I hope i was clear?

    Thanks!

  27. Hello Mr. Ujaval,
    I am trying to get a high resultion csv file for 15 min or 30 min time series from GPM for atleast 5 years. Do you have any resources for me to work with? I tried the code you posted earlier, it says my memory limit has exceed for a yearly range.
    Thanks!

  28. I’m attempting to compute the Standardised Precipitation Index (SPI) using CHIRPS data at the 1, 3, 6, 9, and 12-month scales. I’m using the java script that un-spider offers. I’d like to compute the 3-month sum in such a way that the sum of 3 months for January is November+December+January, and the sum of three months for February is December+January+February, and so on.
    can you guide me to identify, where and what mistakes I am committing, and a way to correct them.

    https://code.earthengine.google.com/ac4344760762bc29b5844871d29c234a

  29. How to calculate long term monthly or seasonal average rainfall and coefficient of variation for all districts in India

  30. I want to calculate seasonal rainfall for over the years, but my seasonal months are from October to March. rainfall season starts in one year and complete in another year. the list sequence I saw on other codes is (1,12) and (10,3) is not accepted. please help

    • Modify the function like below

      var yearlyRainfall = function(year) {
      var startDate = ee.Date.fromYMD(year, 10, 1)
      var endDate = startDate.advance(6, 'month')
      .......

  31. I have a question about classification

    1. I managed to make a classification model with 9 classes
    how do I make predictions based on 1 class from the classifier, e.g say cropland only to the entire region, and then calculate NDVI for that class only in the region

  32. Hello. I am confused about why the total precipitation value for Bangalore is 1336.52 mm, but there are pixels on the map image with values such as 1436. Shouldnt the pixels in the map layer add all up to 1336? meaning there should be such high values and only values that can add up to the total precipitation?

    • Precipitation values are summed over time to get total precipitation. Each pixel represents total rainfall at that pixel for the year. If you want to know total precipitation in a region, you have to calculate “average” of all pixels in the region to obtain average rainfall depth over the region, not “sum”.

  33. Dear Dr. Ujaval, thank you for an amazing tutorial. I am trying to get the monthly average rainfall of multiple counties in a Region across several years. how would you suggest I do that? Thank in Advance for your assistance

  34. Hello, thanks for the good work you are doing, i highly apply,
    if my area of interest is small, it implies that this data would be of a low spatial resolution, how best can i resample it in GEE, PLEASE help in modifying the code

    • Resampling won’t work. You cannot magically get high resolution data from low resolution data. You only have a single estimate for the pixel ( which represents 5 km x 5 km area). There are no higher resolution precipitation estimates available.

Leave a Reply to ujavalCancel reply