# Calculating month of minimum NDVI per pixel using Google Earth Engine

I have been trying to generate an `ee.Image` object where each pixel value contains the number of the month where average NDVI is at a minimum. So the output image should have pixel values from 1-12, where 1 indicates January has the lowest mean NDVI values, 2 indicates February, etc.

I first calculated the maximum values for each month across the time series. Then I took the mean across all Januarys, all Februarys etc. to produce the mean monthly NDVI cycle as follows:

``````// Find MODIS NDVI images for relevant date range
var start_date = ee.Date("2010-01-01");
var end_date = ee.Date("2020-01-01");

var modis_filtered = ee.ImageCollection("MODIS/006/MOD13Q1")
.filterDate(start_date, end_date)
.select("NDVI");

// Calculate monthly max NDVI values
var monthly_images = function(IC) {

// Get number of months in interval
var n_months = ee.List.sequence(0, end_date.difference(start_date, "month").round().subtract(1));

// Iterate monthly max over all months in the interval
var images = n_months.map(function(n) {

// Get images for given month
var filtered = IC.filterDate(start, end);

var max = filtered.mean();

return max.set("month", start.get("month"), "year", start.get("year"));
});

return ee.ImageCollection.fromImages(images);
};

var ndvi_monthly_max = monthly_images(modis_filtered);

// Calculate average monthly cycle
var month_list = ee.List.sequence(1, 12);

var cycle = ee.ImageCollection.fromImages(month_list.map(function(x) {
return ndvi_monthly_max.filter(ee.Filter.eq("month", x))
.mean()
.set("month", x);
}));
``````

This gives an ImageCollection with one Image for each month. It's then simple to calculate the minimum value for each pixel, but I can't figure out a clean way to calculate which month that minimum occurs in. The best I have come up with is:

1. Calculate the minimum across all months,
2. Test whether the pixel values in each month are equal to that minimum,
3. Replace all matching pixels in each month with the month index, and mask the rest,
4. Mosaic the resulting 12 images together.
``````var min_ndvi_month = cycle.map(function(image) {
// Image containing month number
var month_image = ee.Image.constant(image.get("month"))
.toInt16();
// Replace pixel with month number if it is equal to min; otherwise mask
var is_min = image.eq(min_ndvi);

return is_min_month;
});

// Mosaic output to one image
var output = min_ndvi_month.mosaic();

Map.addLayer(output, {min: 1, max: 12}, "month of min NDVI");
print(output);
``````

This seems to work, but seems ugly, convoluted and error prone! Is there a better way?

Add a month band to each image (an integer from 1 to 12) and use the numInputs option to ee.Reducer.min() to get the month band that goes along with the min value. And since you're taking the mean of the means, so you don't need to map over months twice; you can use `calendarRange` instead of `filterDate` to just get all the images for month N from all years in the first function.

``````var month_list = ee.List.sequence(1, 12);
var monthly_images = ee.ImageCollection.fromImages(month_list.map(function(n) {
var filtered = modis_filtered.filter(ee.Filter.calendarRange(n, n, 'month'))
var mean = filtered.mean();
var monthBand = ee.Image.constant(n).int().rename('month')
• Thanks! I needed to edit the code to run without error - the month number can be added as `ee.Image.constant(n)` rather than `ee.Image.constant(start.get("month"))` in this case, and `monthly_images` needs to be converted to an ImageCollection for the reducer to work. But this approach does what I asked so I have marked it as the answer. Commented Nov 12, 2021 at 11:34