# Vector averaging wind direction using focal buffers in R?

I have a raster of 1 km wind direction data that I need to run a focal buffer on. Instead of using the default buffering mean function, I need to use vector averaging since my wind direction is in degrees (e.g. (360+0)/2 = 180/South, instead of 360/North!).

I tried using the circular mean function from the circular package, but this doesn't work with rasters.

How do I perform vector average focal buffers on rasters?

I wrapped `avgWind` function around circular mean but still get the same error.

``````library(raster)
library(circular)

# creating a sample raster for stackoverflow
xy <- matrix(sample(0:359), 10, 10)
r <- raster(xy)

avgWind <- function(r, units) {
r_avg <- mean(circular(r, units = "degrees"))
return(r_avg)
}

r_buf <- focal(r, focalWeight(r, d=20, type='circle')
,fun = avgWind(r)
,na.rm = T)

Error in x/180 : non-numeric argument to binary operator
In class(x) <- c("circular", cl) :
Setting class(x) to multiple strings ("circular", "RasterLayer", ...); result will no longer be an S4 object
``````

EDIT

After applying obrl_soil's example to my projected data the buffered data appears to be inverted.  • Your fun argument needs to be an actual function. – Jeffrey Evans Nov 28 '18 at 4:18
• I still get the same error after wrapping circular into its own function. – philiporlando Nov 28 '18 at 4:25
• I'd usually decompose to horizontal and vertical components of the wind and average those, then calculate the direction again. Do you have magnitude as well as direction? – mdsumner Nov 28 '18 at 5:17
• The syntax problem needed to fix here is delete "(r)" from "avgWind(r)" - it wants the function, not a return value from it. (But running this code crashes R for me so I'd check what avgWind is returning) – mdsumner Nov 28 '18 at 5:22
• My 32GB workstation could handle it, but it's crashing on my 4GB laptop too. I'll look into calculating horizontal and vertical components of wind direction/magnitude and see what I can do. – philiporlando Nov 28 '18 at 5:50

`focalWeight` appears designed to work on a projected raster, so I think half the problems you're having actually come from the reprex you've built. Terrible irony! To build a circular filter for unprojected data, I like the method in this blog post:

``````make_circ_filter <- function(radius, res) {
sweeper<-function(mat){
for(row in 1:nrow(mat)){
for(col in 1:ncol(mat)){
dist<-sqrt((as.numeric(dimnames(mat)[])[row])^2 +
(as.numeric(dimnames(mat)[])[col])^2)
}
}
return(mat)
}
out<-sweeper(circ_filter)
return(out)
}

cf <- make_circ_filter(5, 1)
# for an efficient mean filter, adjust the non-NA values
# in cf to 1/n where n is the number of non-NA cells, and
# then set NA to 0
cf[which(cf == 1)] <- 1/length(cf[!is.na(cf)])
cf[which(is.na(cf))] <- 0
``````

## EDIT

Ok the technical note you've supplied has a much better solution. So here's how I would spatialise it:

``````library(raster)
library(slga)

# handy data
aoi <-  c(148.3, -21.2, 148.7, -20.8)
aspect <- slga::get_lscape_data('ASPCT', aoi )
fake_speed <- slga::get_lscape_data('SLPPC', aoi) # its really slope >.>

# then follow tech note method to average wind
deg2rad <- function(deg) {(deg * pi) / (180)}

# calculate components u and v

# run focal on each component to get a spatial mean
avg_comp_u <- focal(dir_comp_u, cf)
avg_comp_v <- focal(dir_comp_v, cf)

# back-convert
function(cell) {
if(any(is.na(cell))) {
NA_real_
} else {
atan2(cell, cell)
}})

# and then to degrees
• The spatial buffers are working, but the final output appears to be inverted. I've added comparison figures of my projected data, swapping `cf` for a `focalWeight` parameter. I've gone through the math several times and haven't figured out where the problem is yet. – philiporlando Nov 29 '18 at 1:20
• I was missing a negative sign when calculating `dir_comp_u` and `dir_comp_v`. It only took me a few weeks to figure it out ha! Thanks again for all of your help on this! – philiporlando Dec 24 '18 at 6:10