1

I have a raster stack containing 84 layers each of which corresponds to 1 month of rainfall from November 1999 to October 2006. I have named the layers in my raster stack 199911 to 200610 i.e. year followed by month. I also have a spatial points dataframe where each row has a date in identical format.

I want to extract from the raster stack the sum of all the rainfall between the date of a row and the previous October at that row's spatial location. So if a row's date was 20006 (June 2000) it would sum all the rainfall at that row's location between 199910 (October 1999) and 20006. As I have lots of data I want to automate this process.

I've tried to get this to work but with no joy. Does anyone have any tips?

James
  • 1,164
  • 2
  • 15
  • 36

1 Answers1

1

Here's one option:

library(raster)

# Vector of dates
dates <- format(seq(as.Date('1999/1/11'), as.Date('2006/1/10'), by='month'), '%Y%m')

# RasterStack with random data
s <- setNames(stack(replicate(length(dates), raster(matrix(runif(100), 10)))), 
              paste0('rain', dates))

# Create a SpatialPointsDataFrame with some random dates and coords
d <- data.frame(x=runif(10), y=runif(10), date=sample(dates, 10))
coordinates(d) <- ~x+y

# Split the spdf by date
d_by_date <- split(d, d$date)

# Extract values
rain_sum <- unsplit(lapply(d_by_date, function(x) {
  # current year
  y <- as.numeric(substr(x$date, 1, 4))
  # current month
  m <- as.numeric(substr(x$date, 5, 6))
  # if month is after Oct, start from that year's Oct
  # if month is before Oct, start from previous year's Oct
  if(m < 11) y <- y-1
  start_date <- as.Date(sprintf('%s/10/01', y))
  # if start_date is earlier than first time slice, reset to first time slice
  start_date <- max(min(as.Date(sub('rain', '01', names(s)), '%d%Y%m')), start_date)
  end_date <- as.Date(paste0(x$date, '01'), '%Y%m%d')
  # Sequence of dates to sum over
  i <- format(seq(start_date, end_date, by='month'), 'rain%Y%m')
  # Extract values and sum
  sum(extract(s[[i]], x))
}), d$date)
jbaums
  • 27,115
  • 5
  • 79
  • 119
  • Thanks for the help jbaums! Unfortunately I can't get the code to work for me, I keep getting both a warning and an error. I think the "if" statement will only check the first entry so I'll try writing a for loop and see if that helps. Warning message: In if (m < 11) y <- y - 1 : the condition has length > 1 and only the first element will be used Error in format(seq(start_date, end_date, by = "month"), "rain%Y%m") : error in evaluating the argument 'x' in selecting a method for function 'format': Error in seq.Date(start_date, end_date, by = "month") : 'to' must be of length 1 – James Apr 26 '16 at 08:52
  • I've got the code to work for me and have edited your answer to reflect the changes I made. Most notably I swapped your lapply in favour of a for loop. Have accepted your answer. – James Apr 28 '16 at 15:20
  • Except for some reason my edit wasn't accepted...go figure. – James Apr 29 '16 at 10:15