## Summarizing Circular Data in R: Aspect Angle

Submitted by dylan on Wed, 2012-10-10 15:26.

The orientation of terrain surface (aspect) can have dramatic effects on landscape-scale variation in soil temperature and moisture. Summarizing aspect angle is complicated by the fact that sampled values are measured on a circular scale. The circular package for R can be used to summarize, model, and visualize this type of data.

An example function is presented below that demonstrates several components of the circular package: special data structures, summary functions, plotting functions and their application to circular data derived from measurements collected by compass. Spread and central tendency are depicted with a combination of circular histogram and kernel density estimate. The circular mean, and relative confidence in that mean are depicted with an arrow: longer arrow lengths correspond to greater confidence in the mean.

Circular Histogram

Code Example

# load library (you may have to install this library first)
library(circular)

# plot a vector of aspect measurements, with units of degrees, measured via compass
aspect.plot <- function(p, p.bins=60, p.bw=30, p.axis=seq(0, 350, by=10), plot.title=NULL) {
# remove NA
p <- na.omit(p)

# make a circular class object: using native degrees, template sets zero and direction
c.p <- circular(p, units='degrees', template="geographics")

# compute the mean
m.p <- mean(c.p)

# compute mean resultant length
rho.p <- rho.circular(c.p)

# setup custom axis
a.p <- circular(p.axis, units='degrees', template="geographics")

# circular histogram
plot(c.p, axes=FALSE, stack=TRUE, bins=p.bins, shrink=1.45, cex=1, sep=0.06, pch=21, col=1, bg='RoyalBlue')

# add circular density, bw is the smoothness parameter
lines(density(c.p, bw=p.bw), col='RoyalBlue', lty=2)

# add axes: note work-around for strange bug...
axis.circular(at=(-a.p) + 90, labels=a.p, cex=0.6)

# annotate north
text(0, 1.125, 'North', cex=0.85, font=1)

# annotate mean with an arrow
arrows.circular(m.p, shrink=rho.p, length=0.15, col='RoyalBlue')

text(0, -0.25, plot.title, cex=0.85, font=2)
}

# generate some fake data
p.narrow <- runif(n=25, min=215, max=280)
p.wide <- runif(n=25, min=0, max=270)

# set figure margins to 0, 2-column plot
par(mar=c(0,0,0,0), mfcol=c(1,2))

# plot
aspect.plot(p.narrow, p.bw=10, plot.title='Soil A')
aspect.plot(p.wide, p.bw=10, plot.title='Soil B')

( categories: )